一. 概念
Exchanger能在兩個線程驅動的任務之間交換對象。交換之前,A任務持有D1對象,B任務持有D2對象。交換之後,A任務持有D2對象,B任務持有D1對象。
Exchanger可以使用的場景:
1. 大數據量、多步驟執行的任務
比如把整個任務分割成了n段。第一段子任務在執行到某種程度後,執行Exchanger exchange( )操作,把已經加工好的數據傳遞給第二段子任務,每段任務由不同的線程來驅動,整體上加快了任務的處理速度。
2. 基因算法
二. 使用方式
1. Exchanger( )
構造函數,創建一個新的Exchanger對象
/**
* Creates a new Exchanger.
*/
public Exchanger() {
participant = new Participant();
}
2. exchange(V x)
互換對象。兩個任務必須同時調用exchange( )互換纔會成功。當一個任務調用了Exchanger對象的exchange( )後,它將被阻塞住,直到另一個任務也調用了同一個Exchanger對象的exchange( )方法,此時x對象的互換操作纔會成功。
三. 案例
本例中創建了一個生產者和消費者,生產者生產Fat對象,消費者消費Fat對象,對象之間藉助Exchanger,互換List<Fat>集合。
1. 生產者
private Generator<T> generator;
private Exchanger<List<T>> exchanger;
private List<T> holder;
public ExchangerProducer(Exchanger<List<T>> exchanger, Generator<T> gen, List<T> holder) {
this.exchanger = exchanger;
this.generator = gen;
this.holder = holder;
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
for(int i = 0; i < ExchangerDemo.size; i++) {
holder.add(generator.next());
}
holder = exchanger.exchange(holder);
}
} catch (InterruptedException e) {
System.out.println("OK to terminate this way");
}
}
}
2. 消費者
class ExchangerConsumer<T> implements Runnable {
private Exchanger<List<T>> exchanger;
private List<T> holder;
private volatile T value;
public ExchangerConsumer(Exchanger<List<T>> exchanger, List<T> holder) {
this.exchanger = exchanger;
this.holder = holder;
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
holder = exchanger.exchange(holder);
for (T x : holder) {
// 此處在遍歷列表時,移除了元素。爲了不報錯ConcurrentModificationException,
// 所以使用CopyOnWriteArrayList
value = x;
holder.remove(x);
}
}
}catch (InterruptedException e) {
System.out.println("OK to terminate this way");
}
System.out.println("Final value: " + value);
}
}
3. main方法
public class ExchangerDemo {
static int size = 10;
static int delay = 5;
public static void main(String[] args) throws Exception{
if(args.length > 0) {
size = Integer.parseInt(args[0]);
}
if(args.length > 1) {
delay = Integer.parseInt(args[1]);
}
ExecutorService exec = Executors.newCachedThreadPool();
Exchanger<List<Fat>> xc = new Exchanger<>();
List<Fat> producerList = new CopyOnWriteArrayList<>();
List<Fat> consumerList = new CopyOnWriteArrayList<>();
exec.execute(new ExchangerProducer<>(xc, BasicGenerator.create(Fat.class), producerList));
exec.execute(new ExchangerConsumer<>(xc, consumerList));
TimeUnit.SECONDS.sleep(delay);
exec.shutdownNow();
}
}
4. 執行結果
OK to terminate this way
Final value: Fat id:90189
OK to terminate this way