Java多線程: Exchanger的使用

一. 概念

         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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章