同步工具类可以根据自身的状态来协调线程的控制流。
同步工具类都包含特定的结构化属性,封装了一些状态,这些状态觉得指定同步工具类的线程是继续执行还是等待。同时,提供了操作状态的方法。
阻塞队列不仅能作为保存对象的容器,还能协调生产者和消费者等线程之间的控制流。take和put等方法将阻塞,直到队列达到期望的状态。
闭锁是一种同步工具类,可以延迟线程进度直到其到达终止状态。闭锁的作用相当于一扇门,闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当结束时,这扇门会打开,并且允许所有线程通过。闭锁可以用来确保某些活动直到其他活动都完成后才继续执行。
比如:确保某个计算在所有依赖的资源都被初始化之后才继续执行,等到直到某个操作的所有参与者都准备就绪再继续执行。
闭锁状态包括计数器,被初始化为一个整数,等待的每个任务完成之后-1,当计数器变成0之后表示等待的所有事件都已经完成了,可以进行后续的计算了。
CountDownLatch是一种实现。
FutureTask通过Callable来实现的,有三种状态,等待运行、正在运行和运行完成。完成包括正常结束、取消导致结束和异常导致结束。
当程序中有耗时的操作,并且可以分为多个可以并行执行的流程,然后最后聚合结果的时候,可以考虑使用FutureTask来加速执行
public T someMethod(){
FutureTask<T> task1= new FutureTask(....);
FutureTask<T> task2= new FutureTask(....);
FutureTask<T> task3= new FutureTask(....);
executor.submit(task1);
executor.submit(task2);
executor.submit(task3);
try{
task1.get();
task2.get();
task3.get();
// 聚合操作
}catch(Exception e){
// 异常处理
}
// ...
}
计数信号量可以控制同时访问某个特定资源的操作数量。
Semaphore中管理者一组虚拟的permit,在初始化时指定数量,执行之前先获取许可,使用之后释放。
栅栏类似于闭锁,能阻塞一组线程知道某个事件发生。
区别:栅栏与闭锁关键区别在于所有线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,栅栏用于等待其他线程(参考:https://www.cnblogs.com/steffen/p/11244715.html)。CyclicBarrier是一种实现,可以使一定数量的参与方反复在栅栏位置执行。
Exchanger也是另一种栅栏,可以用于两个线程之间交换数据,可以参考(https://www.jianshu.com/p/990ae2ab1ae0,https://blog.csdn.net/octopusflying/article/details/80634864)