一、wait和notify
- wait和notify方法不是Thread特有的方法,而是Object的方法
-
- wait方法
public final void wait() throws InterruptedException
public final void wait(long timeout) throws InterruptedException
public final void wait(long timeout, int nanos) throws InterruptedException
wati的三个重载方法都将调用wait(long timeout)方法,wait等价于wait(0),0代表永不超时。
(1) Object的wait(long timeout)方法会导致当前线程进入阻塞,直到有其他线程调用了此Object的notify或者notifyAll方法唤醒,或者阻塞时间达到timeout自动唤醒。
(2) wait方法必须拥有该对象的monitor,也就是wait方法必须在同步方法中使用。
(3) 当前线程执行了wait方法后,放弃对该monitor的所有权并进入与该对象关联的wait set中其他线程可以继续争抢该monitor的所有权。
- wait方法
-
- notify方法
唤醒单个正在执行该对象wait方法的线程。
如果某个线程由于执行该对象的wait方法而进入阻塞则会被唤醒,如果没有则忽略。
被唤醒的线程需要重新获取对该对象所关联的monitor的lock才能继续执行。
- notify方法
二、wait和notify例子
- EventQueue.java
package communication;
import java.util.LinkedList;
/**
* @ClassName EventQueue
* @Description TODO
* wait和notify方法不是Thread特有的方法,而是Object的方法
* 1. wait方法
* public final void wait() throws InterruptedException
* public final void wait(long timeout) throws InterruptedException
* public final void wait(long timeout, int nanos) throws InterruptedException
* wati的三个重载方法都将调用wait(long timeout)方法,wait等价于wait(0),0代表永不超时
* (1) Object的wait(long timeout)方法会导致当前线程进入阻塞,直到有其他线程调用了此
* Object的notify或者notifyAll方法唤醒,或者阻塞时间达到timeout自动唤醒。
* (2) wait方法必须拥有该对象的monitor,也就是wait方法必须在同步方法中使用。
* (3) 当前线程执行了wait方法后,放弃对该monitor的所有权并进入与该对象关联的wait set中
* 其他线程可以继续争抢该monitor的所有权
* 2. notify方法
* 唤醒单个正在执行该对象wait方法的线程
* 如果某个线程由于执行该对象的wait方法而进入阻塞则会被唤醒,如果没有则忽略
* 被唤醒的线程需要重新获取对该对象所关联的monitor的lock才能继续执行
* @Author Cays
* @Date 2019/3/13 15:54
* @Version 1.0
**/
public class EventQueue {
private final int max;
static class Event{
}
//队列,多线程共享资源,加锁处理
private final LinkedList<Event> eventQueue=new LinkedList<>();
private final static int DEFAULT_MAX_EVENT=10;
public EventQueue(){
this(DEFAULT_MAX_EVENT);
}
public EventQueue(int max){
this.max=max;
}
//提交一个Event到队尾
public void offer(Event event){
synchronized (eventQueue){
//多线程修改为while
if (eventQueue.size()>=max){
try {
console(" the queue is full.");
//如果队列满线程会阻塞,wait
//如果满了,等待消费者消费
eventQueue.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
console(" the new event is submitted");
eventQueue.addLast(event);
//多线程改为notifyAll()同时唤醒所有阻塞线程
eventQueue.notify();
}
}
//从队头获取数据,如果队头没有数据,工作线程阻塞
public Event take(){
synchronized (eventQueue){
//多线程修改为while
if (eventQueue.isEmpty()){
try {
console(" the queue is empty.");
//如果满了,等待生产者生产
eventQueue.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
Event event=eventQueue.removeFirst();
//多线程改为notifyAll()同时唤醒所有阻塞线程
this.eventQueue.notify();
console(" the event "+event+" is handled.");
return event;
}
}
private void console(String message){
//线程调用wait方法被加入到与monitor关联的wait set中,一个
//线程调用notify()唤醒一个线程,notifyAll()唤醒所有线程
System.out.println(Thread.currentThread().getName()+":"+message);
}
}
- EventClient.java
package communication;
import java.util.concurrent.TimeUnit;
/**
* @ClassName EventClient
* @Description TODO
* 生产者与消费者问题
* wait和notify的注意事项:
* 1. wait方法是可中断方法,当前线程一旦调用wait方法进入阻塞状态,其他线程可以使用
* interrupt方法将其打断,同时interrupt标识被擦除。
* 2. 线程执行了某个对象的wait方法之后,加入与之对应的wait set中,每一个对象的monitor
* 都有与之关联的wait set。
* 3. 当一个线程进入wait set后,notify方法可以将其唤醒,从wait set中弹出,同时中断wait
* 中的线程也将被唤醒。
* 4. 必须在同步方法中使用wait和notify方法,因为执行wait和notify的前提是必须持有同步
* 方法的monitor的所有权。
* 5. 同步代码的monitor必须与执行wait notify方法的对象一致,用哪个对象的monitor同步,
* 就只能用哪个对象进行wait和notify操作。
* @Author Cays
* @Date 2019/3/13 21:30
* @Version 1.0
**/
public class EventClient {
public static void main(String []args){
final EventQueue eventQueue=new EventQueue();
new Thread(()->{
for (;;){
eventQueue.offer(new EventQueue.Event());
}
},"Producer").start();
new Thread(()->{
for (;;){
eventQueue.take();
try {
TimeUnit.MILLISECONDS.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
}
},"Consumer").start();
}
}
执行结果: