线程通信#
等待通知机制#
等待通知模式是Java中比较经典的线程通信方式。
两个线程通过对同一对象调用等待wait()和通知notify()方法来进行通讯。
示例:
TwoThreadWaitNotify
需要注意的细节,如下
使用
wait()、notify()和notifyAll()时需要先对调用对象加锁。调用
wait()方法后,线程状态由RUNNING变为WAITING,并将当前线程放置到对象的等待队列。notify()或notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或notifAll()的线程释放锁之后,等待线程才有机会从wait()返回。notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中,而notifyAll()方法则是将等待队列中所有的线程全部移到同步队列,被移动的线程状态由WAITING变为BLOCKED。从
wait()方法返回的前提是获得了调用对象的锁。
WaitNotify.java运行过程

等待通知的经典范式#
等待方遵循如下原则
获取对象的锁。
如果条件不满足,那么调用对象的
wait()方法,被通知后仍要检查条件。条件满足则执行对应的逻辑。
synchronized(对象) {
while(条件不满足) {
对象.wait();
}
对应的处理逻辑
}
通知方遵循如下原则
获得对象的锁。
改变条件。
通知所有等待在对象上的线程。
synchronized(对象) {
改变条件
对象.notifyAll();
}
join()方法#
示例:
JoinTest
从源码可以看出,join()也是利用的等待通知机制。核心逻辑:
while (isAlive()) {
wait(0);
}
volatile共享内存#
因为Java是采用共享内存的方式进行线程通信的,所以可以采用以下方式用主线程关闭A线程
示例:
VolatileTest
CountDownLatch并发工具#
示例:
CountDownLatchTest
CountDownLatch也是基于AQS(AbstractQueuedSynchronizer)实现的:
初始化一个
CountDownLatch时告诉并发的线程,然后在每个线程处理完毕之后调用countDown()方法。该方法会将
AQS内置的一个state状态-1。最终在主线程调用
await()方法,它会阻塞直到state == 0的时候返回。
CyclicBarrier并发工具#
示例:
CyclicBarrierTest
CyclicBarrier中文名叫做屏障或者是栅栏,也可以用于线程间通信。它可以等待N个线程都达到某个状态后继续运行的效果。
首先初始化线程参与者。
调用
await()将会在所有参与者线程都调用之前等待。直到所有参与者都调用了
await()后,所有线程从await()返回继续后续逻辑。
线程响应中断#
示例:
StopThread
可以采用中断线程的方式来通信,调用了thread.interrupt()方法其实就是将thread中的一个标志属性置为了true。
并不是说调用了该方法就可以中断线程,如果不对这个标志进行响应其实是没有什么作用(这里对这个标志进行了判断)。
但是如果抛出了InterruptedException异常,该标志就会被JVM重置为false。
线程池awaitTermination()方法#
示例:
AwaitTerminationTest
使用awaitTermination()方法的前提需要关闭线程池,如调用了shutdown()方法。
调用shutdown()之后线程池会停止接受新任务,并且会平滑的关闭线程池中现有的任务。
管道通信#
示例:
PipedTest
Java虽说是基于内存通信的,但也可以使用管道通信。
需要注意的是,输入流和输出流需要首先建立连接。这样线程B就可以收到线程A发出的消息了。