Exchanger是一个线程间交换数据的工具类。
Exchanger从字面上可以理解为交换者,是一个可以用于线程间协作的工具类。主要用于线程间的数据交换。Exchanger提供一个同步点,在这个同步点上,两个线程可以交换彼此的数据。这两个线程可以通过exchange方法交换数据,当然存在线程执行不同步的情况,如果第一个线程先到达同步点,那么在第二个线程到达同步点之前,第一个线程会阻塞等待,直到两个线程都到达同步点,两个线程就可以使用exchange方法交换彼此的数据。
Exchanger可以用于遗传算法得到不同的交配结果。也可以用于校验数据,比如有两个会计师进行账目的对账工作,为了防止出错,系统可以将这两个会计师对账的结果进行比对,从而检查结果是否一致。下面的代码演示了这个场景:
package com.ddkk.patchwork.concurrency.r0407;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* DDKK.COM 弟弟快看,程序员编程资料站 16-4-7.
*/
public class ExchangerDemo {
/**
* 交换器
*/
private static final Exchanger<String> exchanger = new Exchanger<>();
/**
* 线程池
*/
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
/**
*
*/
private static final DateFormat format = new SimpleDateFormat("HH:mm:ss");
/**
* 主线程
* @param args
*/
public static void main(String[] args){
//第一个会计师进行对账
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
String resA = "A's result";
//调用exchange方法表示当前线程已经到达了同步点
exchanger.exchange(resA);
System.out.println(Thread.currentThread().getName() + " arrives at syncPoint at "
+ format.format(new Date()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//第二个会计师进行对账
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
String resB = "B's result";
String resF = exchanger.exchange(resB);
System.out.println(Thread.currentThread().getName() + " arrives at syncPoint at "
+ format.format(new Date()));
System.out.println("Is the data consistent?" + resF.equals(resB)
+ ". A:" + resF + ", B:" + resB + " at " + format.format(new Date()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//关闭线程池
threadPool.shutdown();
}
}
代码执行的结果如下:
程序中如果有一个线程没有到达同步点,则会一直等待,如果不希望一直等待可以使用指定等待时间的exchange(V x,long timeout,TimeUnit unit)指定最长的等待时间。