Java-wait、notify、notifyAll

在java中,线程间的通信可以使用wait、notify、notifyAll来进行控制。
虽然都是跟多线程相关的,但这3个方法并不是Thread类或者是Runnable接口的方法,而是Object类的3个本地方法。
因为在调用这3个方法的时候,当前线程必须获得这个对象的锁,但不是每个对象都是Thread。

关于对象锁,当多个线程都持有同一个对象的时候,如果都要进入synchronized(obj){……}的内部,就必须拿到这个对象的锁,
synchronized的机制保证了同一时间最多只能有1个线程拿到了对象的锁,

关于这3个方法的作用:

  • wait:线程自动释放其占有的对象锁,并等待notify。
  • notify:唤醒一个正在wait当前对象锁的线程,并让它拿到对象锁。
    notify是本地方法,具体唤醒哪一个线程由虚拟机控制。
  • notifyAll:唤醒所有正在wait当前对象锁的线程。
    notifyAll后并不是所有的线程都能马上往下执行,它们只是跳出了wait状态,接下来它们还会是竞争对象锁。

示例

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
62
63
64
65
66
67
68
69
70
71
72
/**
* 消费者
*/
public class Consumer extends Thread{

private Producer producer;

public Consumer(String name,Producer producer){
super(name);
this.producer = producer;
}

/**
* 消费者线程调用waitMsg去获取一个消息实体,
* 如果mList为空,则线程进入wait状态;
*
* 生产者线程每隔3秒钟生产出一个msg实体并放入mList列表,
* 完成后,调用notify唤醒一个消费者线程去消费。
*/
@Override
public void run() {
Message message = producer.waitMsg();
System.out.println("Consumer " + getName() + " get a msg");

// 运行结果;

// 生产者开始 3 秒休眠
// 消费者进入 wait 状态,线程自动释放其占有的对象锁,并等待notify。
// 消费者进入 wait 状态,线程自动释放其占有的对象锁,并等待notify。
// 消费者进入 wait 状态,线程自动释放其占有的对象锁,并等待notify。
// 生产者开始产出 msg 实体
// 唤醒一个正在wait当前对象锁的线程,并让它拿到对象锁。

// 生产者开始 3 秒休眠
// 消费者被 notify 唤醒
// Consumer Consumer1 get a msg
// 生产者开始产出 msg 实体
// 唤醒一个正在wait当前对象锁的线程,并让它拿到对象锁。

// 生产者开始 3 秒休眠
// 消费者被 notify 唤醒
// Consumer Consumer2 get a msg
// 生产者开始产出 msg 实体
// 唤醒一个正在wait当前对象锁的线程,并让它拿到对象锁。

// 生产者开始 3 秒休眠
// 消费者被 notify 唤醒
// Consumer Consumer3 get a msg
// 生产者开始产出 msg 实体
// 唤醒一个正在wait当前对象锁的线程,并让它拿到对象锁。

// 生产者开始 3 秒休眠
// 生产者开始产出 msg 实体
// 唤醒一个正在wait当前对象锁的线程,并让它拿到对象锁。

// 生产者开始 3 秒休眠
// 生产者开始产出 msg 实体
// 唤醒一个正在wait当前对象锁的线程,并让它拿到对象锁。

// 生产者开始 3 秒休眠

}

public static void main(String[] args) {
Producer p = new Producer();
p.start();
new Consumer("Consumer1", p).start();
new Consumer("Consumer2", p).start();
new Consumer("Consumer3", p).start();
}

}
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
/**
* 生产者
*/

public class Producer extends Thread {

private final List<Message> mList = new ArrayList<>();

/**
* 生产者线程每隔3秒钟生产出一个msg实体并放入mList列表,
* 完成后,调用notify唤醒一个消费者线程去消费。
*/
@Override
public void run() {
while (true){
try {
System.out.println("生产者开始 3 秒休眠");
Thread.sleep(3000);
Message message = new Message();
System.out.println("生产者开始产出 msg 实体");
synchronized (mList){
mList.add(message);
mList.notify();
System.out.println("唤醒一个正在wait当前对象锁的线程,并让它拿到对象锁。");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public Message waitMsg(){
synchronized (mList){
if (mList.size() == 0){
try {
System.out.println("消费者进入 wait 状态,线程自动释放其占有的对象锁,并等待notify。");
mList.wait();
System.out.println("消费者被 notify 唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return mList.remove(0);
}
}

}

1
2
3
4
5
6
7
8
/**
* 信息体
*/

public class Message {

}