Thread的方法介绍sleep、join、yield、wait、notify、notifyAll

发布时间 2024-01-10 10:49:55作者: 德邦总管

本文转载自:https://zhuanlan.zhihu.com/p/665014094

 

一、sleep方法(线程锁)

线程释放CPU进入休眠,但不会释放锁(synchronized),释放CPU,不释放锁

这里面有个比较经典的用法,代码中循环太快,导致年轻代的GC频繁或者GC时间久,可以通过Thread.sleep(0)释放CPU,让GC线程去执行回收

经典用法:线程批任务导致cpu占比很高,通过Thread.sleep(0)可以降低CPU占比

二、yield方法(很少用,线程锁)

很少使用,表示当前线程愿意让出CPU执行器的当前使用权,释放CPU,不释放锁,但是调度器可以自由忽略这个提示。

Yield是一种让多线程的执行进度 尽可能一致的方案,比如有4个线程同时执行一样的算法,但是只有两个线程能同时运行,通过Yield,可以让4个线程尽可能在差不多的时间完成

Thread.yield()某种程度上效果等同于Thread.sleep(0)

三、join方法,控制多个线程的执行顺序(线程锁)

常用操作:线程B等线程A执行完成之后再执行,join底层调用的是wait(),会释放CPU,释放线程锁,不会释放对象锁。

 1 private static void demo2() {  
 2     Thread A = new Thread(new Runnable() {  
 3         @Override  
 4         public void run() {  
 5             printNumber("A");  
 6         }  
 7     });  
 8     Thread B = new Thread(new Runnable() {  
 9         @Override  
10         public void run() {  
11             System.out.println("B 开始等待 A");  
12             try {  
13                 A.join();  
14             } catch (InterruptedException e) {  
15                 e.printStackTrace();  
16             }  
17             printNumber("B");  
18         }  
19     });  
20     B.start();  
21     A.start();  
22 }  
23 
24 -- 执行效果
25 B 开始等待 A 
26 A print: 1 
27 A print: 2 
28 A print: 3
29 B print: 1 
30 B print: 2 
31 B print: 3

 

四、wait()和notify()以及notifyAll() (对象锁)

常用操作:两个线程按照指定方式有序交叉运行,wait会释放synchronized锁,释放CPU

经典用法:dubbo底层 调用netty实现RPC调用,dubbo线程调用netty线程之后,进入wait等待状态,netty线程拿到RPC结果后通过notify对dubbo线程进行唤醒

 1 private static void demo3() {  
 2     Object lock = new Object();  
 3     Thread A = new Thread(new Runnable() {  
 4         @Override  
 5         public void run() {  
 6             synchronized (lock) {  
 7                 System.out.println("A 1");  
 8                 try {  
 9                     lock.wait();  
10                 } catch (InterruptedException e) {  
11                     e.printStackTrace();  
12                 }  
13                 System.out.println("A 2");  
14                 System.out.println("A 3");  
15             }  
16         }  
17     });  
18     Thread B = new Thread(new Runnable() {  
19         @Override  
20         public void run() {  
21             synchronized (lock) {  
22                 System.out.println("B 1");  
23                 System.out.println("B 2");  
24                 System.out.println("B 3");  
25                 lock.notify();  
26             }  
27         }  
28     });  
29 
30     A.start();  
31     B.start();  
32 }  
33 
34 -- 输出结果
35 A 1 
36 B 1 
37 B 2 
38 B 3 
39 A 2 
40 A 3

 

wait 和 notify 这个为什么要在 synchronized 代码块中?

线程间传递参数用。

Synchronized 同步关键字可以实现一个互斥条件,通过共享变量来实现多个线程通信的场景里面,参与通信的线程必须要竞争到这个共享变量的锁资源,才有资格对共享变量做修改,修改完成后就释放锁,那么其他的线程就可以再次来竞争同一个共享变量的锁来获取修改后的数据,从而完成线程之前的通信。

五、线程锁和对象锁

对象锁的作用是为了方便多个线程之间交互用,比如线程间参数传递,线程间按指定顺序执行,线程重入,程序员可以根据需要,灵活的控制线程之间的交互

而线程锁比较简单,就是只能控制自己,让自己更CPU玩,无法做到复杂的线程之间的交互