java多线程学习(四) 之 wait和notify

ynchronized让线程之间互斥,但是有时候因为业务逻辑,需要主动释放锁,让其它的线程执行,这就需要线程之间通信,我们知道JAVA里每个对象都有个隐式锁,JAVA为每个对象都提供了wait和notify(还有notifyAll)方法,分别用于本线程主动释放锁,进入等待状态,和唤醒其它进入等待的线程。

官方解释:

Causes the current thread to wait until another thread invokes the java.lang.Object.notify() method or the java.lang.Object.notifyAll() method for this object.
wait会导致当前线程进入等待,直到其它线程执行该对象的notify()或者notifyAll方法
The current thread must own this object’s monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object’s monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
首先当前线程在调用wait之前,必须先获取到该对象的monitor就是所谓的隐式锁,也就是synchronized的作用。这个线程就会释放对隐式锁,并且进入等待,直到另外一个获得锁的线程,通过notify和notifyAll唤醒它。它在被唤醒后,并不会继续往下执行,而是需要再次去获取锁,获取锁之后,继续执行。

也就是说wait和notify(notifyAll)方法必须是在一个线程获取了该对象的隐式锁的情况下,即在synchronized方法,或者synchronized代码段里面,才可以调用,否则就会报错IllegalMonitorStateException – if the current thread is not the owner of this object’s monitor.

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class LockObject
{
    public static void main(String[] args) 
          throws InterruptedException
    {
        final LockObject lock = new LockObject();
 
        new Thread()
        {
 
            @Override
            public void run()
            {
                System.err.println("线程一执行");
                synchronized(lock)
                {
                    try
                    {
                        System.err.println("线程一进入");
                        sleep(3000);
                        System.err.println("线程一睡眠结束");
                        lock.wait();
                        System.err.println("线程一执行结束");
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
 
 
        }.start();;
        Thread.sleep(1000);
        new Thread()
        {
            @Override
            public void run()
            {
                System.err.println("线程二执行");
                synchronized(lock)
                {
                    try
                    {
                        System.err.println("线程二进入");
                        sleep(3000);
                        System.err.println("线程二睡眠结束");
                        lock.notify();
                        System.err.println("线程二通知别人醒来");
                        sleep(2000);
                        System.err.println("线程二执行结束");
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}

输出:
线程一执行
线程一进入
线程二执行
线程一睡眠结束
线程二进入
线程二睡眠结束
线程二通知别人醒来
线程二执行结束
线程一执行结束

解释:
首先进入线程一,synchronized(lock)让其获取lock的隐式锁,线程二阻塞。
当线程一直线到wait的时候,释放锁, 线程二获取锁开始进入。
当线程二直线到notify执行之后,线程一被唤醒。
但是线程一还无法继续往下执行,因为它要重新获取锁,目前锁还被线程二所有,当线程二结束之后,释放锁,线程一重新得到锁,执行结束。

备注:
还有void wait(long timeout)方法,可以让线程在wait多少毫秒之后自助唤醒。
还有notifyAll()方法,用于三个或者以上个线程,多线程等待的情况,notifyAll用于唤醒所有wait的线程,notify只唤醒其中的某一个线程。

留言

提示:你的email不会被公布,欢迎留言^_^

*

验证码 *