我们都知道Java Object 中的 wait() 和 notify() 方法可以进行线程间的通信。
wait() 方法: 当前线程释放对象锁(监视器)的拥有权,在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,当前线程处于等待状态。
notify() 方法:唤醒在此对象锁(监视器)上等待的单个线程。如果有多个线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并且根据实现进行选择。
这里说的一点就是,调用当前线程 noitfy() 后,等待的获取对象锁的其他线程(可能有多个)不会立即从 wait() 处返回,而是需要调用 notify() 的当前线程释放锁(退出同步块)之后,等待线程才有机会从 wait() 返回。这点自己之前理解得不清晰,举个例子加深一下:
等待线程:
public class WaitThread implements Runnable{
Object lock;
public WaitThread(Object lock){
this.lock = lock;
}
public void run() {
String threadName = Thread.currentThread().getName();
synchronized (lock){
System.out.println(threadName + "开始进入同步代码块区域");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + "准备离开同步代码块区域");
}
}
}
唤醒线程:
public class NotifyThread implements Runnable{
Object lock;
public NotifyThread(Object lock){
this.lock = lock;
}
public void run() {
String threadName = Thread.currentThread().getName();
synchronized (lock){
System.out.println(threadName + "开始进入同步代码块区域");
lock.notify();
try {
System.out.println(threadName + "业务处理开始");
// 暂停 2s 表示业务处理
Thread.sleep(2000);
System.out.println(threadName + "业务处理结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + "准备离开同步代码块区域");
//lock.notify();放在这一行唤醒,效果一样
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + "退出同步代码块后续操作");
}
}
注意:lock.notify() 的位置和放在注释的位置,效果一样的,线程都会在执行完synchronized同步代码块之后才会释放锁,其他处于 wait() 线程才有可能被唤醒。
主程序:
public class Test {
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Thread waitThread = new Thread(new WaitThread(lock), "waitThread");
Thread notifyThread = new Thread(new NotifyThread(lock), "notifyThread");
waitThread.start();
Thread.sleep(1000);
notifyThread.start();
}
}
输出结果:
waitThread开始进入同步代码块区域
notifyThread开始进入同步代码块区域
notifyThread业务处理开始
notifyThread业务处理结束
notifyThread准备离开同步代码块区域
waitThread准备离开同步代码块区域
notifyThread退出同步代码块后续操作
可以看到waitThread线程必须等到notifyThread线程退出同步块释放锁之后,才会从 wait() 处返回。lock.notify() 放在注释掉的那一行,输出结果不变。不过在平常工作中,还是建议把 notify() 放在容易理解的位置。