在多线程程序中,很多时候需要让多个线程相互合作完成一个任务,这要求线程间能够进行协调。
例如:任务A和B是完成一项工作的两个划分,只有A任务计算出结果后,任务B才能开始计算。我们再将任务A划分为4个子任务,交给4个线程并行执行,由于子任务有大小区分,处理小任务的线程有可能很快就执行完毕了,因此该任务需要等待其他线程执行完成后,才能继续向下执行任务B;这时候我们需要用到线程障栅。
CyclicBarrier 类是一个同步辅助类,实现了一个称为障栅的集合点,在不是所有线程都到达集合点前,线程之前可以相互等待。Cyclic 的含义是“循环的,周期的”,代表该障栅在所有等待的线程到达集合点并被释放后可以循环使用。
CyclicBarrier 类比较适合于线程数量固定的情况。
1、CyclicBarrier(int parties) //创建障栅对象;parties为需要等待的线程个数。 2、CyclicBarrier(int parties,Runnable barrierAction) // barrierAction 定义最后一个进入障栅的线程要执行的动作。
在障栅的对象上可以调用 await() 方法,该方法需要放置到 try…catch…语句块中,并捕获 InterruptedException 和 BrokenBarrierException 异常。线程在完成自己的工作后调用 await() 方法等待。当最后一个线程调用 await() 方法后,将唤醒所有等待线程,并继续该障栅后的工作。
倒计时门闩就像一个带有计数器开关的门,只有在门前等待的线程到达一定数量时,门闩才会打开,线程才可以继续执行。
倒计时门闩由 CountDownLatch 类实现,该类从 Object 继承而来,可以通过一个给定的值进行初始化,通常在同步状态中保存的是当前的计数值,线程调用 await() 方法等待;方法 countDown() 会导致计数值递减,当计数值为零时,所有的倒计时门闩范围内的等待线程的阻塞状态将解除。
CountDownLatch(int count)
其中,count 为初始计数,必须为正数,否则将抛出 IllegalArgumentException 异常。
信号量机制通常用于限制对于某个资源同时访问的线程数量。
信号量机制是一种典型的同步机制,可以用于解决常用的线程同步问题。
在 Java 并发库中,类 Semaphore 可以实现信号量机制,其定义如下:
public class Semaphore extends Object implements Serializable
信号量管理了一个许可集合,可以通过方法 acquire() 获取一个许可,如果没有许可则可以等待。通过方法 release() 可以释放一个许可。
Semaphore(int permits) // 用给定的许可数创建一个 Semaphore 对象。
Semaphore(int permits,boolean fair) // 设置许可分配策略:公平分配/非公平分配
使用场景:
银行设置了4个窗口可以同时办理业务,现在有20个顾客需要办理业务,使用信号量机制可以实现这种场景。
同步队列是一个没有数据缓冲的阻塞队列,在同步队列上插入操作必须等待相应的删除执行完成后才能执行,反之亦然。
不能调用peek() 方法查看队列中是否有数据,也不允许对整个队列遍历。
类 SynchronousQueue 是 Java 集合框架中的一员。该类的定义形式如下:
public class SynchronousQueue
extends AbstraceQueue
implements BlockingQueue,Serializable
其中 E 指明同步队列中元素的类型。
public SynchronousQueue()
public SynchronousQueue(boolean fair) //使用公平性策略创建同步队列
使用场景:使用同步队列实现生产者和消费者的问题。
由于使用同步队列作为公共缓冲区,故生产者和消费者对公共缓冲区的操作不再需要添加额外的同步控制操作。
生产者对缓冲区进行插入操作,消费者对缓冲区进行删除操作。两者协同操作,不允许一个人连续执行两次。
从 JDK1.5 版本开始提供了线程间数据交换的功能,该功能可以通过 Exchanger 类完成。
public class Exchanger(V) extends Object
参数 V 表示要交换数据的类型。
该类从 Object 类继承,它提供了一个同步点,在该同步点上线程间可以交换数据。一个线程通过 exchange() 方法将其数据提供给另一个线程,并接受另一个线程的数据。
V exchange( V x)
该方法将等待另一个线程到达交换点,然后交换指定的数据 x,该方法将返回的交换后的数据。
在日常生活中,我们在做一件事情的时候,习惯把一件事情划分为若干个阶段,然后规定每个阶段的任务和完成的时间,从而实现阶段化的控制和管理,阶段化处理往往在完成某一项工作时很高效。
从 JDK1.7 版本开始引入类 Phaser,它是 Java 并发库中功能强大并且较复杂的一个功能,可以用来完成阶段式的并发执行任务的功能。
Phaser 类直接从 Object 类继承,它是一个可复用的同步障栅,与 CyclicBarrier 和 CountDownLatch 功能类似,但使用上更加灵活。