一、定義
每個線程將條目上的某個方法呈現給 exchange 方法,與夥伴線程進行匹配,並且在返回時接收其夥伴的對象。Exchanger 可能被視爲 SynchronousQueue 的雙向形式。Exchanger 可能在應用程序(比如遺傳算法和管道設計)中很有用。
內存一致性效果:對於通過 Exchanger 成功交換對象的每對線程,每個線程中在 exchange() 之前的操作 happen-before 從另一線程中相應的 exchange() 返回的後續操作。(內存一致性效果被稱爲happen-before),簡單的例子:當一個線程進行寫入操作,另一個線程進行讀取操作,保證一個線程寫入的結果對另一個線程的讀取是可視的。
二、用法
package cn.itcast.heima2;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExchangerTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger<String> exchanger = new Exchanger<>();
service.execute(new Runnable(){
public void run() {
try {
String data1 = "恭喜發財!";
System.out.println("線程" + Thread.currentThread().getName() +
"正在把數據:" + data1 +"換出去");
Thread.sleep((long)(Math.random()*10000));
String data2 = exchanger.exchange(data1);
System.out.println("線程" + Thread.currentThread().getName() +
"換回的數據爲:" + data2);
}catch(Exception e){
}
}
});
service.execute(new Runnable(){
public void run() {
try {
String data1 = "乖,給你一個紅包!";
System.out.println("線程" + Thread.currentThread().getName() +
"正在把數據:" + data1 +"換出去");
Thread.sleep((long)(Math.random()*10000));
String data2 = exchanger.exchange(data1);
System.out.println("線程" + Thread.currentThread().getName() +
"換回的數據爲:" + data2);
}catch(Exception e){
}
}
});
}
}
三、JDK中的例子
使用 Exchanger
在線程間交換緩衝區,因此,在需要時,填充緩衝區的線程獲取一個新騰空的緩衝區,並將填滿的緩衝區傳遞給騰空緩衝區的線程。
class FillAndEmpty {
Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>();
DataBuffer initialEmptyBuffer = ... a made-up type
DataBuffer initialFullBuffer = ...
class FillingLoop implements Runnable {
public void run() {
DataBuffer currentBuffer = initialEmptyBuffer;
try {
while (currentBuffer != null) {
addToBuffer(currentBuffer);
if (currentBuffer.isFull())
currentBuffer = exchanger.exchange(currentBuffer);
}
} catch (InterruptedException ex) { ... handle ... }
}
}
class EmptyingLoop implements Runnable {
public void run() {
DataBuffer currentBuffer = initialFullBuffer;
try {
while (currentBuffer != null) {
takeFromBuffer(currentBuffer);
if (currentBuffer.isEmpty())
currentBuffer = exchanger.exchange(currentBuffer);
}
} catch (InterruptedException ex) { ... handle ...}
}
}
void start() {
new Thread(new FillingLoop()).start();
new Thread(new EmptyingLoop()).start();
}
}