Java多线程:wait()和notify()方法详解

通过前面的内容我们知道,当一个线程正在执行某个对象中被synchronized关键字修饰的方法时,这个对象锁上,其他线程必须等到当前线程执行完后才能访问。

这个整个过程可以用下图来表示

一个正在运行的线程想要执行synchronized方法,必须要获得当前对象的锁,如果没有获得则当前对象的锁则会被阻塞在对象锁池当中,直到前一个线程释放了该对象锁,当前线程重新获取到对象锁时,线程恢复到可运行状态,当cpu给它资源时,线程将处于运行状态。

有上图可见,对于多个线程执行一个synchronized方法,我必须在当前线程执行完后,后面的线程才有机会访问该方法。那如果我就是想在前一个线程执行方法过程中停下来,转而让当前线程执行该方法时,该怎么办?

这个时候我们就需要使用 wait() 和 notify() 方法了。

在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。

Object类中关于等待/唤醒的API详细信息如下:
notify()        -- 唤醒在此对象监视器上等待的单个线程。
notifyAll()    -- 唤醒在此对象监视器上等待的所有线程。
wait()                     -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout)     -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。如果 timeout 为零,则不考虑实际时间,在获得通知前该线程将一直等待。
wait(long timeout, int nanos)  -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。

所以上面的整个流程描述如下:

如果当前线程正执行某个synchronized方法时,在synchronized方法内遇到了wait()方法,这时当前线程将阻塞在对象等待池中同时释放掉该对象锁,在对象锁池中等待的线程将争取获得此锁,获得锁的线程将回到Runnable状态。当某个线程调用notify()或者notifyAll方法时()在等待池中的线程将被唤醒,进入到锁池中等待获取锁。(线程调用了notify()或notifyAll()方法时并不会释放锁,并不能让处于wait中的线程立刻执行,只是将其唤醒进入锁池等待获取锁)

先调用notify()方法,然后在调用wait()方法。这时从notify()到wait()方法之间的这一段代码仍会执行,原因就是:虽然调用notify(),但另外的线程没有获得锁,它还在对象锁池中待着,直到当前线程执行wait()方法释放当前锁才会执行它的方法。

wait与notify方法都是定义在Object类中,而且是final的,因此会被所有的Java类所继承并且无法重写。这两个方法要求在调用时线程应该已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或块当中。当线程执行了wait方法时,它会释放掉对象的锁。
另一个会导致线程暂停的方法就是Thread类的sleep方法,它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。

看一个例子

 1 public class Sample
 2 {
 3     private int number;
 4 
 5     public synchronized void increase()
 6     {
 7         while (0 != number)
 8         {
 9             try
10             {
11                 wait();
12             }
13             catch (InterruptedException e)
14             {
15                 e.printStackTrace();
16             }
17         }
18 
19         number++;
20 
21         System.out.println(number);
22 
23         notify();
24     }
25 
26     public synchronized void decrease()
27     {
28         while (0 == number)
29         {
30             try
31             {
32                 wait();
33             }
34             catch (InterruptedException e)
35             {
36                 e.printStackTrace();
37             }
38         }
39 
40         number--;
41 
42         System.out.println(number);
43 
44         notify();
45     }
46 }
 1 public class MainTest
 2 {
 3     public static void main(String[] args)
 4     {
 5         Sample sample = new Sample();
 6         
 7         Thread t1 = new IncreaseThread(sample);
 8         Thread t2 = new DecreaseThread(sample);
 9         
10         Thread t3 = new IncreaseThread(sample);
11         Thread t4 = new DecreaseThread(sample);
12         
13         t1.start();
14         t2.start();
15         t3.start();
16         t4.start();
17     }
18 }

打印结果为0/1交替出现。

原文地址:https://www.cnblogs.com/2015110615L/p/6733812.html