最近重新看了一下多线程方面的,对于 Object 本身提供的三个方法 wait(),notify(),notifyAll() 都没有好好研究过,大多都是基于书籍跟文档而已,所以重新用代码跑了一遍记录一下,加深下印象。
1、wait()
官方文档是这样描述的:
Causes the current thread to wait until another thread invokes the{@link java.lang.Object#notify()} method or the {@link java.lang.Object#notifyAll()} method for this object. In other words, this method behaves exactly as if it simply performs the call {@code wait(0)}.
简单来说就是只有调用了 notify() 方法或者 notifyAll() 才能唤醒当前调用了 wait() 方法的线程。
也是就是调用了 wait() 方法的线程会进入等待状态。
文档后面还有一段话:
* This method should only be called by a thread that is the owner * of this object's monitor. See the {@code notify} method for a * description of the ways in which a thread can become the owner of * a monitor.也就是说只有持有改对象的锁(监视器 monitor)才可以调用 wait() 方法,调用之后会把当前的监视器(锁)交给其他线程。
2、notify()
文档描述如下:
* Wakes up a single thread that is waiting on this object's * monitor. If any threads are waiting on this object, one of them * is chosen to be awakened. The choice is arbitrary and occurs at * the discretion of the implementation. A thread waits on an object's * monitor by calling one of the {@code wait} methods.
唤醒任意一个在等到获取监视器(锁 monitor)的线程,并且是随机的,只能唤醒一个。
同样也有跟 wait() 方法类似的一段描述:
* This method should only be called by a thread that is the owner * of this object's monitor. A thread becomes the owner of the * object's monitor in one of three ways:
该方法也是必须在持有对象的锁(监视器 monitor)才可以调用。
3、notifyAll()
文档描述:
* Wakes up all threads that are waiting on this object's monitor. A * thread waits on an object's monitor by calling one of the * {@code wait} methods.
跟 notify() 的不同就是 notifyAll() 唤醒的是所有 wait 中的线程。但是唤醒的不是立即执行,必须等待当前线程执行完成之后,等待唤醒的线程才会去竞争获取 monitor。
并且 notifyAll() 与 notify() 一样,也是必须在持有对象的 monitor 的时候才可以调用。
4、代码验证
4.1、多线程单对象调用 wait()
public class MyTest {
public synchronized void t1(String name){
System.out.println(name + ":t1 method");
}
public synchronized void t2(String name){
System.out.println(name + ":t2 method with wait()");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ":t2 method with wait() after notify");
}
public synchronized void t3(String name){
System.out.println(name + ":t3 with notify");
notify();
System.out.println(name + ":t3 after notify");
}
public static void main(String[] args) throws InterruptedException {
MyTest test = new MyTest();
new Thread(new Runnable() {
@Override
public void run() {
test.t1("Thread 1");
test.t2("Thread 1");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.t1("Thread 2");
test.t2("Thread 2");
}
}).start();
}
}
输出结果如下并且主线程一直处于等待状态没有结束:
Thread 1:t1 method
Thread 1:t2 method with wait()
Thread 2:t1 method
Thread 2:t2 method with wait()
4.2、多线程单对象调用 wait(),调用 notify()
在4.1 的基础上,main 方法改成如下:
public static void main(String[] args) throws InterruptedException {
MyTest test = new MyTest();
new Thread(new Runnable() {
@Override
public void run() {
test.t1("Thread 1");
test.t2("Thread 1");
test.t1("Thread 1");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.t1("Thread 2");
test.t2("Thread 2");
}
}).start();
// 确保线程1跟2都已经跑了
Thread.sleep(1000);
new Thread(new Runnable() {
@Override
public void run() {
test.t3("Thread 3");
}
}).start();
}
输出结果如下,并且当前主线程处于等待阻塞状态:
Thread 2:t1 method
Thread 2:t2 method with wait()
Thread 1:t1 method
Thread 1:t2 method with wait()
Thread 3:t3 with notify
Thread 3:t3 after notify
Thread 2:t2 method with wait() after notify
很明显当执行了 Thread 3 的时候,处于 wait 状态的 Thread 1 跟 2 都在等待 Thread 3 执行之后加入竞争获取 minor,多执行几遍会发现之后一句话的结果可能是下面两句其中一句,因为只有一个线程会被唤醒。
Thread 2:t2 method with wait() after notify
Thread 1:t2 method with wait() after notify
4.3、多线程单对象调用 wait(),调用 notifyAll()
延用4.2的main方法,但是需要改下 t3() 的 notify 为 notifyAll
输出结果如下:
Thread 1:t1 method
Thread 1:t2 method with wait()
Thread 2:t1 method
Thread 2:t2 method with wait()
Thread 3:t3 with notify
Thread 3:t3 after notify
Thread 2:t2 method with wait() after notify
Thread 1:t2 method with wait() after notify
很明显,Thread 1跟2 都被唤醒了并且执行完。
总结:
wait 与 notify/notifyAll 都是搭配使用,并且是对于同一对象同一个锁的情况下,执行 wait 的对象释放的锁需要等到其他线程调用 notify/notifyAll 并且执行完当前线程才有机会被唤醒继续执行下去。