剑指JUC原理-3.线程常用方法及状态
常用方法



start和run
调用run
public static void main(String[] args) {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug(Thread.currentThread().getName());FileReader.read(Constants.MP4_FULL_PATH);}};t1.run();log.debug("do other things ...");
}
输出:
19:39:14 [main] c.TestStart - main
19:39:14 [main] c.FileReader - read [1.mp4] start ...
19:39:18 [main] c.FileReader - read [1.mp4] end ... cost: 4227 ms
19:39:18 [main] c.TestStart - do other things ...
程序仍在 main 线程运行, FileReader.read() 方法调用还是同步的
调用start
将上述代码的 t1.run() 改为 t1.start
输出:
19:41:30 [main] c.TestStart - do other things ...
19:41:30 [t1] c.TestStart - t1
19:41:30 [t1] c.FileReader - read [1.mp4] start ...
19:41:35 [t1] c.FileReader - read [1.mp4] end ... cost: 4542 ms
此时再t1线程执行,而FileReader.read() 方法调用是异步的
总结
直接调用run是在主线程中执行了run,并没有启用新的线程,而使用start是启动新的线程,通过新的线程简介执行了run中的代码。
sleep和yield
sleep
**调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)**以一段代码为例
Thread t1 = new Thread("t1") {@Overridepublic void run() {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}};t1.start();System.out.println("t1 state: "+ t1.getState());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1 state: "+ t1.getState());
输出:
t1 state: RUNNABLE
t1 state: TIMED_WAITING
其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("enter sleep...");try {Thread.sleep(2000);} catch (InterruptedException e) {log.debug("wake up...");e.printStackTrace();}}};t1.start();Thread.sleep(1000);log.debug("interrupt...");t1.interrupt();
输出:
enter sleep...
wake up...
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at test2$1.run(test2.java:10)
睡眠结束后的线程未必会立刻得到执行
睡眠结束,可能还在处理其他的线程,需要等待cpu调度器调度
yield
本质上是让出cpu的使用权, 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程。具体的实现依赖于操作系统的任务调度器
线程优先级
线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
如果 cpu 比较忙,那么优先级高的线程会获得更多的时间片,但 cpu 闲时,优先级几乎没作用
join方法详解
为什么需要join?
下面的代码执行,打印 r 是什么?
log.debug("开始");Thread t1 = new Thread(() -> {log.debug("开始");sleep(1);log.debug("结束");r = 10;},"t1");t1.start();// t1.join();log.debug("结果为:{}", r);log.debug("结束");
分析:
- 因为主线程和线程 t1 是并行执行的,t1 线程需要 1 秒之后才能算出 r=10
- 而主线程一开始就要打印 r 的结果,所以只能打印出 r=0
解决方案:
- 用 sleep 行不行?为什么?不能精准的把控执行结束的时间。
- 用 join,加在 t1.start() 之后即可**(可选)**
以调度的角度来讲,如果
- 需要等待结果返回,才能继续运行就是同步
- 不需要等待结果返回,就能继续运行就是异步

等待多个结果
Thread t1 = new Thread(() -> {sleep(1);r1 = 10;
});
Thread t2 = new Thread(() -> {sleep(2);r2 = 20;
});
long start = System.currentTimeMillis();
t1.start();
t2.start();t1.join();
t2.join();long end = System.currentTimeMillis();
log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
分析:
实际上,2s执行完成,为什么呢?因为 两个线程都是同时启动的,无论t1.join 和 t2.join那个在前那个在后,其最终都会对两个线程分别的阻塞等待,只因为两个线程是同时启动的。
所以结果时不变的,效果图如下:

有时效的join
等待时间
Thread t1 = new Thread(() -> {sleep(1);r1 = 10;});long start = System.currentTimeMillis();t1.start();// 线程执行结束会导致 join 结束t1.join(1500);long end = System.currentTimeMillis();log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
输出:
20:48:01.320 [main] c.TestJoin - r1: 10 r2: 0 cost: 1010
其实就是如果 执行完时间在 join 等待时间内,那么join同步阻塞就是有效的,否则
没等够时间
Thread t1 = new Thread(() -> {sleep(2);r1 = 10;});long start = System.currentTimeMillis();t1.start();// 线程执行结束会导致 join 结束t1.join(1500);long end = System.currentTimeMillis();log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
输出:
20:52:15.623 [main] c.TestJoin - r1: 0 r2: 0 cost: 1502
interrupt 方法详解
打断 sleep,wait,join 的线程 ,这几个方法都会让线程进入阻塞状态,而打断阻塞状态的线程,会清空打断状态,同时抛出一个 InterruptedException 异常。
打断标记
在 Java 中,每个线程都有一个称为 “打断标记”(interrupt flag)的状态位。这个状态位用于标识线程是否被请求中断。
当一个线程通过调用另一个线程的 interrupt() 方法来请求中断时,被请求中断的线程的打断标记会被设置为 “true”。这意味着被请求中断的线程可以检查自己的打断标记来判断是否被中断,并根据需要采取相应的操作。
打断标记不会直接中断线程的执行,而是提供了一种机制,让线程能够感知到中断请求并根据情况作出响应。具体的响应方式由线程自身决定,可以是终止线程、抛出异常或执行其他适当的操作。
在 Java 中,可以使用 Thread.interrupted() 方法来检查当前线程的打断标记,并清除标记(将其设置为 “false”)。还可以使用 Thread.isInterrupted() 方法来检查线程的打断标记,但不会清除标记。
需要注意的是,打断标记只是一个指示线程是否被请求中断的标志,它不会自动中断线程的执行。线程在执行过程中需要自行检查打断标记,并根据需要采取相应的操作来处理中断请求。
打断阻塞线程
Thread t1 = new Thread(()->{sleep(1);}, "t1");t1.start();sleep(0.5);t1.interrupt();log.debug(" 打断状态: {}", t1.isInterrupted());
输出:
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at java.lang.Thread.sleep(Thread.java:340)at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)at cn.itcast.n2.util.Sleeper.sleep(Sleeper.java:8)at cn.itcast.n4.TestInterrupt.lambda$test1$3(TestInterrupt.java:59)at java.lang.Thread.run(Thread.java:745)
21:18:10.374 [main] c.TestInterrupt - 打断状态: false
此时可以看到,不仅抛出 InterruptedException 异常,同时打断状态设置为 false
打断正常线程
使用 interrupt() 方法来打断正在运行的线程不会立即停止线程的执行。它只是设置了线程的打断标记为 “true”,并且如果线程处于等待状态(如 sleep()、wait()、join() 等),它会立即抛出 InterruptedException 异常。
打断正常运行的线程, 不会清空打断状态
Thread t2 = new Thread(()->{while(true) {Thread current = Thread.currentThread();boolean interrupted = current.isInterrupted();if(interrupted) {log.debug(" 打断状态: {}", interrupted);break;}}}, "t2");t2.start();sleep(0.5);t2.interrupt();
输出:
20:57:37.964 [t2] c.TestInterrupt - 打断状态: true
终止模式之两阶段终止模式
在一个线程 T1 中如何“优雅”终止线程 T2?这里的【优雅】指的是给 T2 一个料理后事的机会。
使用线程对象的stop方法停止线程
stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁!!1 所以这个方法不妥
使用 System.exit(int) 方法停止线程
目的仅是停止一个线程,但这种做法会让整个程序都停止
两阶段终止模式
以一个监控系统为例

如果有被打断,那么就料理后事,结束循环,如果没有被打断,那么 首先睡眠 2s,如果无异常,那么就正常的执行监控记录,然后继续循环,如果有异常,因为 使用interrupt 如果线程是阻塞的,会抛出 InterruptedException异常同时 重置标志位,所以需要重新设置打断标记。
public void start(){thread = new Thread(() -> {while(true) {Thread current = Thread.currentThread();if(current.isInterrupted()) {log.debug("料理后事");break;}try {Thread.sleep(1000);log.debug("将结果保存");} catch (InterruptedException e) {// 打断 sleep后会清除 打断标记,所以需要重新设置打断标记current.interrupt();}}},"监控线程");thread.start();}public void stop() {thread.interrupt();}
输出:
11:49:42.915 c.TwoPhaseTermination [监控线程] - 将结果保存
11:49:43.919 c.TwoPhaseTermination [监控线程] - 将结果保存
11:49:44.919 c.TwoPhaseTermination [监控线程] - 将结果保存
11:49:45.413 c.TestTwoPhaseTermination [main] - stop
11:49:45.413 c.TwoPhaseTermination [监控线程] - 料理后事
主线程与守护线程
默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。(默认情况下,主线程是守护线程还是非守护线程)
log.debug("开始运行...");
Thread t1 = new Thread(() -> {log.debug("开始运行...");sleep(2);log.debug("运行结束...");
}, "daemon");
// 设置该线程为守护线程
t1.setDaemon(true);
t1.start();
sleep(1);
log.debug("运行结束...");
输出:
08:26:38.123 [main] c.TestDaemon - 开始运行...
08:26:38.213 [daemon] c.TestDaemon - 开始运行...
08:26:39.215 [main] c.TestDaemon - 运行结束...
注意:
垃圾回收器线程就是一种守护线程
Tomcat 中的 Acceptor 和 Poller 线程都是守护线程,所以 Tomcat 接收到 shutdown 命令后,不会等待它们处理完当前请求
原理解读:
这句话的意思是,在Tomcat服务器中,Acceptor(接收器)和Poller(轮询器)线程都被设置为守护线程。当Tomcat接收到关闭命令时,它不会等待这些线程处理完当前正在进行的请求。
在Tomcat中,Acceptor线程负责接收新的连接请求,而Poller线程负责处理已建立的连接上的I/O操作。由于它们是守护线程,它们的运行不会阻止Tomcat服务器的关闭过程。
当接收到关闭命令时,Tomcat会立即停止接受新的连接请求,并开始关闭已经建立的连接。但是,由于Acceptor和Poller线程是守护线程,它们可能无法处理完当前正在进行的请求,因为守护线程会随着主线程的结束而立即停止。
因此,这句话的含义是,Tomcat在接收到关闭命令后,不会等待Acceptor和Poller线程处理完当前请求,而是立即停止它们的运行,以便尽快关闭服务器。
五种状态
这是从 操作系统 层面来描述的

【初始状态】仅是在语言层面创建了线程对象,还未与操作系统线程关联(相当于 new了线程还没有start)
【可运行状态】(就绪状态)指该线程已经被创建(与操作系统线程关联),可以由 CPU 调度执行
【运行状态】指获取了 CPU 时间片运行中的状态,当 CPU 时间片用完,会从【运行状态】转换至【可运行状态】,会导致线程的上下文切换
【阻塞状态】
- 如果调用了阻塞 API,如 BIO 读写文件,这时该线程实际不会用到 CPU,会导致线程上下文切换,进入
【阻塞状态】 - 等 BIO 操作完毕,会由操作系统唤醒阻塞的线程,转换至【可运行状态】
- 与【可运行状态】的区别是,对【阻塞状态】的线程来说只要它们一直不唤醒,调度器就一直不会考虑
调度它们
【终止状态】表示线程已经执行完毕,生命周期已经结束,不会再转换为其它状态
六种状态
这是从Java API层面上来描述
根据 Thread.State 枚举,分为六种状态
public enum State {/*** Thread state for a thread which has not yet started.*/NEW,/*** Thread state for a runnable thread. A thread in the runnable* state is executing in the Java virtual machine but it may* be waiting for other resources from the operating system* such as processor.*/RUNNABLE,/*** Thread state for a thread blocked waiting for a monitor lock.* A thread in the blocked state is waiting for a monitor lock* to enter a synchronized block/method or* reenter a synchronized block/method after calling* {@link Object#wait() Object.wait}.*/BLOCKED,/*** Thread state for a waiting thread.* A thread is in the waiting state due to calling one of the* following methods:* <ul>* <li>{@link Object#wait() Object.wait} with no timeout</li>* <li>{@link #join() Thread.join} with no timeout</li>* <li>{@link LockSupport#park() LockSupport.park}</li>* </ul>** <p>A thread in the waiting state is waiting for another thread to* perform a particular action.** For example, a thread that has called <tt>Object.wait()</tt>* on an object is waiting for another thread to call* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on* that object. A thread that has called <tt>Thread.join()</tt>* is waiting for a specified thread to terminate.*/WAITING,/*** Thread state for a waiting thread with a specified waiting time.* A thread is in the timed waiting state due to calling one of* the following methods with a specified positive waiting time:* <ul>* <li>{@link #sleep Thread.sleep}</li>* <li>{@link Object#wait(long) Object.wait} with timeout</li>* <li>{@link #join(long) Thread.join} with timeout</li>* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>* </ul>*/TIMED_WAITING,/*** Thread state for a terminated thread.* The thread has completed execution.*/TERMINATED;}
这也是为什么能分成六种状态的原因

- NEW 线程刚被创建,但是还没有调用 start() 方法
- RUNNABLE 当调用了 start() 方法之后,注意,Java API 层面的 RUNNABLE 状态涵盖了 操作系统 层面的
【可运行状态】、【运行状态】和【阻塞状态】(在Java中,阻塞状态可以由多种原因引起,例如线程等待锁、等待输入/输出完成等。需要注意的是,由于Java的I/O模型通常使用阻塞式的BIO(Blocking I/O),所以在Java中无法区分不同类型的阻塞状态,仍然将其归类为RUNNABLE状态) - BLOCKED , WAITING , TIMED_WAITING 都是 Java API 层面对【阻塞状态】的细分
- TERMINATED 当线程代码运行结束
以一段代码来详解这六种状态吧。
Thread t1 = new Thread("t1") {@Overridepublic void run() {System.out.println("running...");}};Thread t2 = new Thread("t2") {@Overridepublic void run() {while(true) { // runnable}}};t2.start();Thread t3 = new Thread("t3") {@Overridepublic void run() {System.out.println("running...");}};t3.start();Thread t4 = new Thread("t4") {@Overridepublic void run() {synchronized (test.class) {try {Thread.sleep(1000000); // timed_waiting} catch (InterruptedException e) {e.printStackTrace();}}}};t4.start();Thread t5 = new Thread("t5") {@Overridepublic void run() {try {t2.join(); // waiting} catch (InterruptedException e) {e.printStackTrace();}}};t5.start();Thread t6 = new Thread("t6") {@Overridepublic void run() {// t4先上锁,t6就拿不到了synchronized (test.class) { // blockedtry {Thread.sleep(1000000);} catch (InterruptedException e) {e.printStackTrace();}}}};t6.start();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1 state "+ t1.getState());System.out.println("t2 state "+ t2.getState());System.out.println("t3 state "+ t3.getState());System.out.println("t4 state "+ t4.getState());System.out.println("t5 state "+ t5.getState());System.out.println("t6 state "+ t6.getState());
输出:
t1 state NEW
t2 state RUNNABLE
t3 state TERMINATED
t4 state TIMED_WAITING
t5 state WAITING
t6 state BLOCKED
以这段代码为例,t1其实就是新建状态,t2相当于正在运行中,t3相当于运行结束,t456相当于阻塞的三种状态,4是 sleep阻塞,5是join阻塞,6是获取不到锁阻塞。
各状态资源占用情况
在Java线程的各个状态中,不同状态下线程所占用的资源情况如下:
- 新建状态(New):在新建状态下,线程并不占用任何系统资源,只是占用了一些内存空间来存储线程对象本身的信息。
- 可运行状态(Runnable):在可运行状态下,线程占用了一些系统资源,包括程序计数器、虚拟机栈和一些线程私有数据。这些资源主要用于保存线程的执行上下文和局部变量等信息。
- 运行状态(Running):在运行状态下,线程会占用CPU资源,以便执行线程的任务。此时,除了占用的CPU资源外,线程还会继续占用可运行状态下的资源。
- 阻塞状态(Blocked):在阻塞状态下,线程暂时不占用CPU资源,但仍然占用了一些系统资源。具体资源的占用情况取决于线程被阻塞的原因。例如,如果线程因为等待获取锁而被阻塞,那么它会占用一定数量的锁资源和等待队列。
- 等待状态(Waiting):在等待状态下,线程通常不占用CPU资源和锁资源,但仍然占用了一些系统资源。这些资源包括等待队列、条件变量和一些其他线程同步机制所需的资源。
- 终止状态(Terminated):在终止状态下,线程不再占用任何系统资源。它的执行上下文和局部变量等信息都会被释放,线程对象本身也可以被垃圾回收。
需要注意的是,不同状态下线程所占用的资源情况是动态变化的。线程的状态会根据线程的调度、等待条件的满足以及任务的完成而发生变化。因此,在编写多线程程序时,需要注意合理管理线程的状态和资源,以避免资源的浪费和性能的下降。
相关文章:
剑指JUC原理-3.线程常用方法及状态
常用方法 start和run 调用run public static void main(String[] args) {Thread t1 new Thread("t1") {Overridepublic void run() {log.debug(Thread.currentThread().getName());FileReader.read(Constants.MP4_FULL_PATH);}};t1.run();log.debug("do othe…...
MYSQL8-sql语句使用集合。MYCAT-sql语法使用集合
MYSQL 1.MYSQL事务与锁问题处理 SELECT * FROM information_schema.INNODB_LOCKs; -- 查询锁select * from information_schema.INNODB_LOCK_WAITS; -- 查询等待锁SELECT * FROM information_schema.INNODB_TRX; -- 查询事务select * from information_schema.processlist wh…...
UNIX 域协议(本地通信协议)
概述 Unix 域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务通信的一种方式。是进程间通信(IPC)的一种方式。 它提供了两类套接字:字节流套接字 SOCK_STREAM(有点像 TCP)和数据报套接字 SOCK_…...
分类预测 | MATLAB实现SSA-CNN-BiGRU-Attention数据分类预测(SE注意力机制)
分类预测 | MATLAB实现SSA-CNN-BiGRU-Attention数据分类预测(SE注意力机制) 目录 分类预测 | MATLAB实现SSA-CNN-BiGRU-Attention数据分类预测(SE注意力机制)分类效果基本描述模型描述程序设计参考资料 分类效果 基本描述 1.MATLA…...
基于FPGA的图像PSNR质量评估计算实现,包含testbench和MATLAB辅助验证程序
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 设置较大的干扰,PSNR15。 设置较小的干扰,PSNR25。 2.算法运行软件版本 matlab2022a vivado2019.2 3.部分核心程序 ti…...
算法进修Day-38
算法进修Day-38 77. 组合 难度:中等 题目要求: 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 示例1 输入:n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 示例2 输入&#…...
8.MySQL内外连接
个人主页:Lei宝啊 愿所有美好如期而遇 目录 表的内连和外连 内连接 外连接 左外连接 右外连接 我们进行演示的表结构是这样的: 表的内连和外连 内连接 内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的…...
使用.NET设计一个Epub电子书生成工具
1. 背景 可能我们接触到更多的小说文件都是普普通通的TXT格式,用于分享的文档更多的是PDF。TXT虽然轻巧,但是不如PDF丰富和强大。而 Epub 电子书格式因为其丰富的展示效果和较小的文件大小,这样一个微妙的平衡就刚刚好。作为一个喜欢看小说的…...
2023-10-26 用C语言实现一个大整数加法
点击 <C 语言编程核心突破> 快速C语言入门 用C语言实现一个大整数加法 前言一、思路和代码设计数字对齐:字符对齐: 二、代码总结 前言 要解决问题: 实现大整数加法 想到的思路: 用字符代替数字, 逐个计算, 过10进位. 其它的补充: 同样思路可以解决减法, 乘法, 但除法…...
[hive] 窗口函数 ROW_NUMBER()
文章目录 ROW_NUMBER() 示例窗口函数 ROW_NUMBER() 在 Hive SQL 中,ROW_NUMBER()是一个用于生成行号的窗口函数。 它可以为查询结果集中的每一行分配一个唯一的行号。 以下是 ROW_NUMBER() 函数的基本语法: ROW_NUMBER() OVER (PARTITION BY column…...
TensorFlow和Pytorch两种机器学习框架的比较及优缺点
TensorFlow是一个开源的机器学习框架,由Google开发并发布,它被用来构建各种类型的机器学习模型,例如图像识别、语音识别、自然语言处理等。TensorFlow主要有以下几个基本概念: Tensor:TensorFlow中最基本的数据结构&am…...
“Can‘t open workbook - unsupported file type: XML“
java开发,增删改查,涉及到导入excel时,有的excel导入失败提示"Cant open workbook - unsupported file type: XML"。着急赶工期,告诉客户先把excel另存为xls格式,再重新导入。现在有点空余时间,好…...
达芬奇MacOS最新中文版 DaVinci Resolve Studio 18中文注册秘钥
DaVinci Resolve Studio 18是一款专业的视频编辑软件,它具有多种强大的功能。首先,它提供了丰富的视频剪辑工具,如剪切、复制、粘贴、剪辑、缩放和移动等,使用户可以轻松地剪辑和组合视频素材。其次,该软件还支持多个轨…...
电脑扬声器未插入?4个方法帮你恢复声音!
“太奇怪了吧,我的电脑扬声器一直显示未插入,我使用电脑的时候也是一直都没有声音。这是为什么呢?我应该怎么解决这个问题呀?” 我们使用电脑播放音频或视频时,都需要用到电脑扬声器。如果扬声器无法播放声音ÿ…...
Python - 通过/SSH 获取远程主机的 env 变量
Python - 通过/SSH 使用远程主机的 env 变量 - IT工具网 (coder.work) ssh.exec_command(. .profile ; cd /home/test/;$run ./test.sh)ssh.exec_command(. .profile ; cd /home/test/;echo $run )...
ubuntu 下的 使用anaconda 环境运行python 项目
pycharm部署django项目到云服务器的详细流程_编程网 anaconda 安装环境 Ubuntu安装Anaconda详细步骤(Ubuntu22.04.1,Anaconda3-2023.03)-CSDN博客 ubuntu下Anaconda安装与使用教程_ubuntu 运行anaconda_fakerth的博客-CSDN博客 Anaconda教…...
MySQL创建定时任务定时执行sql
#删除定时任务 DROP EVENT IF EXISTS user_event ; -- 创建名字为user_event的事件 CREATE EVENT user_event ON SCHEDULE EVERY 1 DAY STARTS DATE_ADD(DATE_ADD(CURDATE(), INTERVAL 1 DAY), INTERVAL 1 HOUR) -- 每隔一天执行一次,开始执行时间为明天凌晨1点整 …...
如何用MFI确定波浪理论第一浪,anzo capital实操演示
通过上文投资者学会了如何确定波浪理论第一浪,但在后台有投资者咨询 :如何用MFI确定波浪理论第一浪,anzo capital昂首资本秉承着有求必应的态度,今天实操进行演示。 在图中,发散用蓝色标注,收敛用绿色。价…...
vscode推送gitee方法
有一套uni-app代码需要修改,版本控制使用vscode的git功能,远程库在gitee上。 1、设置vscode中git.exe路径 由于git使用了绿色便携版(PortableGit-2.42.0.2-64-bit.7z.exe),vscode未识别到git安装路径,需要…...
R语言与作物模型(以DSSAT模型为例)融合应用
随着基于过程的作物生长模型(Process-based Crop Growth Simulation Model)的发展,R语言在作物生长模型和数据分析、挖掘和可视化中发挥着越来越重要的作用。想要成为一名优秀的作物模型使用者与科研团队不可或缺的人才,除了掌握对…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
