wait()和notify()方法主要是用来支持多线程之间的协作。但是这两个方法均为Object的方法,也就是说任何对象都可以调用这两个方法。
比如在线程A中,一个对象实例object调用了wait()方法后,当前线程A就会进入object对象的等待队列(这个等待队列中可能会有多个线程),会停止继续执行,进入等待状态,直到其他线程调用了object.notify()方法后,线程A才有可能继续执行,为什么是有可能呢,因为object.notify()方法被调用时,会从等待队列中随机选择一个线程,将其唤醒,这个选择是不公平的,并不是先等待的线程会优先被选择,这个选择完全是随机的。
示意图如下:
还有一个值得注意的地方是wait()和notify()方法都需要被包含在synchronzied(object)语句中,因为这两个方法都需要获取目标对象的一个监视器,如图所示:
这里有一段测试代码:
package dgb.test.concurrent;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
/**
* @author Dongguabai
* @date 2018/8/31 0:25
*/
@Slf4j
public class WaitAndNotifyTest {
private static final Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(new T1(), "线程一").start();
new Thread(new T1(), "线程二").start();
new Thread(new T1(), "线程三").start();
new Thread(new T1(), "线程四").start();
new Thread(new T1(), "线程五").start();
Thread.sleep(2000);
new Thread(new T2()).start();
new Thread(new T2()).start();
new Thread(new T2()).start();
new Thread(new T2()).start();
new Thread(new T2()).start();
}
static class T1 implements Runnable {
@Override
public void run() {
synchronized (obj) {
try {
log.info(Thread.currentThread().getName() + " 线程【启动】!!!!,当前时间为:{}", LocalDateTime.now());
log.info(Thread.currentThread().getName() + " 正在wait---");
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.info(Thread.currentThread().getName() + " 线程【结束】!!!!,当前时间为:{}", LocalDateTime.now());
}
}
static class T2 implements Runnable {
@Override
public void run() {
synchronized (obj) {
log.info("T2线程【启动】!!!!,当前时间为:{}", LocalDateTime.now());
log.info("T2准备notify---");
obj.notify();
}
log.info("T2线程【结束】!!!!,当前时间为:{}", LocalDateTime.now());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
在上述代码中,由于wait()方法会释放锁,所以可以成功的开启了五个线程并进入等待状态且这五个线程均进入object的等待队列中,2s后开始释放队列中的线程,被释放的线程在得到notify()的通知后,首先会尝试获取object对象锁。
关于wait()和sleep()
这两个方法都可以让线程等待,但是wait()方法可以被唤醒。还有一个重要的区别是wait()会释放目标对象锁,而sleep()不会释放任何资源。
- wait和sleep方法都可以使线程进人阻塞状态。
- wait和sleep方法均是可中断方法,被中断后都会收到中断异常。
- wait是Object的方法,而sleep是Thread特有的方法。
- wait方法的执行必须在同步方法中进行,而sleep则不需要。
- 线程在同步方法中执行sleep方法时,并不会释放monitor的锁,而wait方法则会释放monitor的锁。
- sleep方法短暂休眠之后会主动退出阻塞,而wait方法(没有指定wait时间)则需要被其他线程中断后才能退出阻塞。