博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
notify 和 notifyAll 的区别
阅读量:4079 次
发布时间:2019-05-25

本文共 4304 字,大约阅读时间需要 14 分钟。

(一)先看一个 notify发生死锁的例子:

http://blog.csdn.net/tayanxunhua/article/details/20998449

(本文虽是转载,不过也加入了一些个人观点)
JVM多个线程间的通信是通过 线程的锁、条件语句、以及wait()、notify()/notifyAll组成。
下面来实现一个启用多个线程来循环的输出两个不同的语句:
package
 
com.tyxh.block;
class
 
OutTurn {
    
private
 
boolean
 
isSub
 
=
 
true
;
    
private
 
int
 
count
 
= 0;
    
public
 
synchronized
 
void
 
sub() {
         
 
try
 
{
             
 
while
 
(!
isSub
 
) {
                 
 
this
.wait();
             }
             System.
 
out
.println(
"sub ---- "
 
+
 
count
);
             
 
isSub
 
=
 
false
 
;
             
 
this
.notify();
         }
 
catch
 
(Exception e) {
             e.printStackTrace();
         }
         
 
count
++;
    }
    
public
 
synchronized
 
void
 
main() {
         
 
try
 
{
             
 
while
 
(
isSub
 
) {
                 
 
this
.wait();
             }
             System.
 
out
.println(
"main (((((((((((( "
 
+
 
count
);
             
 
isSub
 
=
 
true
 
;
             
 
this
.notify();
         }
 
catch
 
(Exception e) {
             e.printStackTrace();
         }
         
 
count
++;
    }
}
package
 
com.tyxh.block;
public
 
class
 
LockDemo {
    
public
 
static
 
void
 
main(String[] args) {
         
 
// System.out.println("lock");
         
 
final
 
OutTurn ot =
 
new
 
OutTurn();
         
 
for
 
(
int
 
j = 0; j < 100; j++) {
             
 
new
 
Thread(
new
 
Runnable() {
                 
 
public
 
void
 
run() {
                      
 
// try {
                      
 
// Thread.sleep(10);
                      
 
// } catch (InterruptedException e) {
                      
 
// e.printStackTrace();
                      
 
// }
                      
 
for
 
(
int
 
i = 0; i < 5; i++) {
                          ot.sub();
                      }
                 }
             }).start();
             
 
new
 
Thread(
new
 
Runnable() {
                 
 
public
 
void
 
run() {
                      
 
// try {
                      
 
// Thread.sleep(10);
                      
 
// } catch (InterruptedException e) {
                      
 
// e.printStackTrace();
                      
 
// }
                      
 
for
 
(
int
 
i = 0; i < 5; i++) {
                          ot.main();
                      }
                 }
             }).start();
         }
    }
}
解释一下原因:
     OutTurn类中的sub和main方法都是同步方法,所以多个调用sub和main方法的线程都会处于阻塞状态,等待一个正在运行的线程来唤醒它们。下面分别分析一下使用notify和notifyAll方法唤醒线程的不同之处:
     上面的代码使用了notify方法进行唤醒,而notify方法只能唤醒一个线程,其它等待的线程仍然处于wait状态,假设调用sub方法的线程执行完后(即
System.
 
out
 .println(
"sub ---- "
 
count
 )
执行完之后),所有的线程都处于等待状态,此时在sub方法中的线程执行了isSub=false语句后又执行了notify方法,这时如果唤醒的是一个sub方法的调度线程,那么while循环等于true,则此唤醒的线程也会处于等待状态,此时所有的线程都处于等待状态,那么也就没有了运行的线程来唤醒它们,这就发生了死锁。
     如果使用notifyAll方法来唤醒所有正在等待该锁的线程,那么所有的线程都会处于运行前的准备状态(就是sub方法执行完后,唤醒了所有等待该锁的状态,注:不是wait状态),那么此时,即使再次唤醒一个sub方法调度线程,while循环等于true,唤醒的线程再次处于等待状态,那么还会有其它的线程可以获得锁,进入运行状态。
     总结:notify方法很容易引起死锁,除非你根据自己的程序设计,确定不会发生死锁,notifyAll方法则是线程的安全唤醒方法。
notify和notifyAll的区别:

notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。

void notify(): 唤醒一个正在等待该对象的线程。
void notifyAll(): 唤醒所有正在等待该对象的线程。
两者的最大区别在于:
     notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
     notify他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁,此时如果该对象没有再次使用notify语句,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。
 

 

 

(二)再看一个例子:
https://www.zhihu.com/question/37601861
作者:Alex Wang
链接:https://www.zhihu.com/question/37601861/answer/94679949
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
还是直接上代码:
public class WaitAndNotify {
public static void main(String[] args) {
Object co = new Object(); System.out.println(co); for (int i = 0; i < 5; i++) {
MyThread t = new MyThread("Thread" + i, co); t.start(); }try {
TimeUnit.SECONDS.sleep(2); System.out.println("-----Main Thread notify-----"); synchronized (co) {
co.notify(); } TimeUnit.SECONDS.sleep(2); System.out.println("Main Thread is end."); } catch (InterruptedException e) {
e.printStackTrace(); } }static class MyThread extends Thread {
private String name; private Object co; public MyThread(String name, Object o) {
this.name = name; this.co = o; }@Override public void run() {
System.out.println(name + " is waiting."); try {
synchronized (co) {
co.wait(); } System.out.println(name + " has been notified."); } catch (InterruptedException e) {
e.printStackTrace(); } } }}运行结果:java.lang.Object@1540e19dThread1 is waiting.Thread2 is waiting.Thread0 is waiting.Thread3 is waiting.Thread4 is waiting.-----Main Thread notify-----Thread1 has been notified.Main Thread is end.将其中的那个notify换成notifyAll,运行结果:Thread0 is waiting.Thread1 is waiting.Thread2 is waiting.Thread3 is waiting.Thread4 is waiting.-----Main Thread notifyAll-----Thread4 has been notified.Thread2 has been notified.Thread1 has been notified.Thread3 has been notified.Thread0 has been notified.Main Thread is end.运行环境jdk8,结论:notify唤醒一个等待的线程;notifyAll唤醒所有等待的线程。

你可能感兴趣的文章
STM32中assert_param的使用
查看>>
C语言中的 (void*)0 与 (void)0
查看>>
io口的作用
查看>>
IO口的作用
查看>>
UIView的使用setNeedsDisplay
查看>>
归档与解归档
查看>>
Window
查看>>
为什么button在设置标题时要用一个方法,而不像lable一样直接用一个属性
查看>>
字符串的截取
查看>>
17. Letter Combinations of a Phone Number (DFS, String)
查看>>
93. Restore IP Addresses (DFS, String)
查看>>
19. Remove Nth Node From End of List (双指针)
查看>>
49. Group Anagrams (String, Map)
查看>>
139. Word Break (DP)
查看>>
Tensorflow入门资料
查看>>
剑指_用两个栈实现队列
查看>>
剑指_栈的压入弹出序列
查看>>
剑指_复杂链表的复制
查看>>
服务器普通用户(非管理员账户)在自己目录下安装TensorFlow
查看>>
星环后台研发实习面经
查看>>