CyclcBarrier
在实际应用中,有时候需要多个线程同时工作以完成同一件事情,而且在完成过程中,往往会等待其他线程都完成某一阶段后再执行,等所有线程都到达某一个阶段后再统一执行。
比如有几个旅行团需要途经深圳、广州、韶关、长沙最后到达武汉。旅行团中有自驾游的,有徒步的,有乘坐旅游大巴的;这些旅行团同时出发,并且每到一个目的地,都要等待其他旅行团到达此地后再同时出发,直到都到达终点站武汉。
CountDownLatch
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await
方法会一直受阻塞。之后,会释放所有等待的线程,await
的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
Exchanger
可以在对中对元素进行配对和交换的线程的同步点。每个线程将条目上的某个方法呈现给 exchange
方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象。Exchanger 可能被视为 SynchronousQueue
的双向形式。 Exchanger 可能在应用程序(比如遗传算法和管道设计)中很有用。
用法示例:以下是重点介绍的一个类,该类使用 Exchanger 在线程间交换缓冲区,因此,在需要时,填充缓冲区的线程获取一个新腾空的缓冲区,并将填满的缓冲区传递给腾空缓冲区的线程。
classFillAndEmpty {
Exchanger<DataBuffer>exchanger=newExchanger<DataBuffer>();
DataBuffer initialEmptyBuffer=… a made-up type
DataBuffer initialFullBuffer=…
classFillingLoopimplementsRunnable {
publicvoidrun() {
DataBuffer currentBuffer=initialEmptyBuffer;
try{
while(currentBuffer!=null) {
addToBuffer(currentBuffer);
if(currentBuffer.isFull())
currentBuffer=exchanger.exchange(currentBuffer);
}
}catch(InterruptedException ex) { … handle … }
}
}
classEmptyingLoopimplementsRunnable {
publicvoidrun() {
DataBuffer currentBuffer=initialFullBuffer;
try{
while(currentBuffer!=null) {
takeFromBuffer(currentBuffer);
if(currentBuffer.isEmpty())
currentBuffer=exchanger.exchange(currentBuffer);
}
}catch(InterruptedException ex) { … handle …}
}
}
voidstart() {
newThread(newFillingLoop()).start();
newThread(newEmptyingLoop()).start();
}
}
SynchronousQueue
一种阻塞队列,其中每个 put 必须等待一个 take,反之亦然。同步队列没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行
peek,因为仅在试图要取得元素时,该元素才存在;除非另一个线程试图移除某个元素,否则也不能(使用任何方法)添加元素;也不能迭代队列,因为其中没
有元素可用于迭代。队列的头 是尝试添加到队列中的首个已排队线程元素;如果没有已排队线程,则不添加元素并且头为 null。对于其他
Collection 方法(例如 contains),SynchronousQueue 作为一个空集合。此队列不允许 null 元素。
信号量semaphore
Semaphore 信号量,就是一个允许实现设置好的令牌。也许有1个,也许有10个或更多。
谁拿到令牌(acquire)就可以去执行了,如果没有令牌则需要等待。
执行完毕,一定要归还(release)令牌,否则令牌会被很快用光,别的线程就无法获得令牌而执行下去了。 |
|