# 什么是线程通信

进程是由多个线程组成的,那一个线程是一个 “个体”,多个 “个体” 之间需要经过某些处理,使它们成为一个 “整体”,这样多个线程之间能够更好的合作(交互)。线程之间的通信,可以提高 CPU 的利用率。

就像是一个人 VS 一个团队,那肯定还是团队效率更好。

# 等待通知机制

等待通知机制

等待通知机制的原理 和 现在的外卖小哥与饭店外卖的关系很像:

  1. 我们在手机上下单之后,外卖小哥就会去饭店
  2. 外卖小哥到了饭店后,可能这个时候厨师还没做完,那就需要等等。(这里就是等待)
  3. 厨师什么时候做完饭,外卖小哥就什么时候拿到,这里相当于是厨师通知外卖小哥可以拿外卖了。(就是对应的通知)

# wait 和 notify 方法

wait和notify

wait 方法:将当前线程置入 “预执行队列” 中,并且释放锁,当前线程重新获取到锁后,会从 wait 方法后面的代码继续执行。

notify 方法:用来通知等待对象锁的其他线程,如果有多个线程在等,那么会随机挑一个正在等待的线程把锁给它。

notifyAll 方法:唤醒等待此对象的所有线程。

三个方法调用之前都必须获取到对象级别的锁,不然会报异常。

示例:简单模拟下外卖小哥取餐的流程

public class WaitAndNotifyTest {
private static Object lock = new Object();
public static void main(String[] args) {
Thread takeout = new Thread(() -> {
synchronized (lock) {
System.out.println("外卖员到了,准备取餐");
try {
//进行等待
lock.wait(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("外卖员拿到餐了");

}
}, "外卖小哥");

takeout.start();

Thread cook = new Thread(() -> {
synchronized (lock) {
System.out.println("厨师正在做饭");
try {
//用休眠来模拟厨师正在做饭
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("做好了");
lock.notify();
}
}, "厨师");

cook.start();
}
}

关于上面的例子,只是简单用了下 wait 和 notify 方法。

官方推荐的等待方式是检查 while 循环中正在等待的条件,调用 wait。这种方法避免了可能由虚假唤醒引起的问题。

虚假唤醒: 是一个表象,即在多处理器的系统下发出 wait 的程序有可能在没有 notify 唤醒的情形下苏醒继续执行。

//推荐等待方式:
synchronized (obj) {
while (<condition does not hold> and <timeout not exceeded>) {
long timeoutMillis = ... ; // recompute timeout values int nanos = ... ;
obj.wait(timeoutMillis, nanos);
} ... // Perform action appropriate to condition or timeout
}

# 线程生命周期图

线程生命周期图