java多线程设计wait/notify机制 (synchronized与对象锁)

synchronized(obj) {
    while(!condition) {
        obj.wait();
    }
    obj.doSomething();
}

当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait() , 放弃对象锁.

之后在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:

synchronized(obj) {
    condition = true;
    obj.notify();
}

需要注意的概念是:

# 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {…} 代码段内。

# 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {…} 代码段内唤醒A。

# 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。

# 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。

# obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。

# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。

 

比如下述代码,在SubThread中,如果只是notify,而没有wait,那么SubThread仍然持有lock锁,MyThread虽然被唤醒,但是仍然要等待SubThread执行结束。

Java代码   收藏代码
  1. package test.thread;  
  2.   
  3. //2个线程交替打印。线程1打印奇数,线程2打印偶数  
  4. public class ThreadTest {  
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public static void main(String[] args) {  
  9.         String lock = "lock";  
  10.         MyThread myThread = new MyThread(lock);  
  11.         Thread t1 = new Thread(myThread);  
  12.         t1.start();  
  13.         try {  
  14.             // 确保线程t1先执行  
  15.             Thread.sleep(2000);  
  16.         } catch (InterruptedException e) {  
  17.             e.printStackTrace();  
  18.         }  
  19.         SubThread sub = new SubThread(lock);  
  20.         Thread t2 = new Thread(sub);  
  21.         t2.start();  
  22.     }  
  23. }  
  24.   
  25. class MyThread implements Runnable {  
  26.     String lock;  
  27.   
  28.     public MyThread(String lock) {  
  29.         this.lock = lock;//当前线程获得lock对象的引用  
  30.     }  
  31.   
  32.     public void run() {  
  33.         int i = 0;  
  34.         // 使用lock对象作为监视器  
  35.         synchronized (lock) {//在lock对象上加锁  
  36.             System.out.println("The first thread.获得锁");  
  37.             while (i++ < 20) {  
  38.                 try {  
  39.                     // 每次暂停500毫秒是为了更好地看到效果  
  40.                     Thread.sleep(500);  
  41.                     if (i%2==1) {  
  42.                         System.out.println("The first thread.-->" + i);  
  43.                         // 调用lock监视器的wait()方法,通知本线程释放监视器,本线程等待  
  44.                         // 其他也使用lock对象作为监视器的线程唤醒的时候,本线程得以继续运行  
  45.                         System.out.println("The first thread 被阻塞");  
  46.                         lock.wait();  
  47.                         // 下面的wait(long timeout)表示:若等待5秒后还没有别的线程来唤醒的话,则本线程继续执行  
  48.                         // lock.wait(5000);  
  49.                     }else{  
  50.                         System.out.println("The first thread 解锁lock");  
  51.                         lock.notify();  
  52.                     }  
  53.                     //这个线程当是奇数时,打印数字,打印后,此线程wait。当是偶数时,什么都不做,只是激活lock对象  
  54.                 } catch (InterruptedException e) {  
  55.                     e.printStackTrace();  
  56.                 }  
  57.             }  
  58.         }  
  59.     }  
  60. }  
  61.   
  62. class SubThread implements Runnable {  
  63.     String lock;  
  64.   
  65.     public SubThread(String lock) {  
  66.         this.lock = lock;  
  67.     }  
  68.   
  69.     public void run() {  
  70.         int i = 1;  
  71.         // 这个线程也使用lock对象作为监视器  
  72.         synchronized (lock) {  
  73.             System.out.println("The second thread.获得锁");  
  74.             while (i < 20) {  
  75.                 try {  
  76.                     Thread.sleep(500);  
  77.                     if (i%2==0) {  
  78.                         System.out.println("The second thread.-->" + i);  
  79.                         // 调用lock监视器的wait()方法,通知本线程释放监视器,本线程等待  
  80.                         // 其他也使用lock对象作为监视器的线程唤醒的时候,本线程得以继续运行  
  81.                           
  82.                         System.out.println("The second thread 解锁lock");  
  83.                         lock.notify();  
  84.                           
  85.                         System.out.println("The second thread 被阻塞");  
  86.                         lock.wait();  
  87.                         // 下面的wait(long timeout)表示:若等待5秒后还没有别的线程来唤醒的话,则本线程继续执行  
  88.                         // lock.wait(5000);  
  89.                     }else{  
  90.                         System.out.println("The second thread 什么也没干");  
  91.                         //lock.notify();  
  92.                     }  
  93.                     i++;  
  94.                     //这个线程2,当线程1的wait调用时,此线程2激活。当i是偶数时,打印i,打印后,通知lock解锁(此时thread1得锁,干活),并且此线程2被阻塞  
  95.                 } catch (InterruptedException e) {  
  96.                     e.printStackTrace();  
  97.                 }  
  98.             }  
  99.             // 调用lock对象的notify()方法,唤醒同一对象监视器中调用wait的第一线程  
  100.             // 或者调用notifyAll()方法,唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行  
  101.             //lock.notify();  
  102.         }  
  103.     }  
  104. }  
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值