java并发工具类-Exchanger

img

Exchanger 简介

Exchange位于JUC包下面,主要是用于线程之间数据交换的工具类,经常用于管道设计和遗传算法中,Exchanger用于进行线程间的数据交换,它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange 方法交换数据,如果第一个线程先执行exchange 方法,它会一直等待第二个线程也执行exchange 方法,当两个线程都到达同步点时,这两个线程就可以交换数据。

可以将Exchange看做是一个双向数据传输的SynchronousQueue。

  • 此类提供对外的操作是同步的;
  • 用于成对出现的线程之间交换数据;
  • 可以视作双向的同步队列;
  • 可应用于基因算法、流水线设计等场景。

Exchanger 提供的方法

构造方法

/**
   * Creates a new Exchanger.
   */
  public Exchanger() {
      participant = new Participant();
  }

创建一个新的Exchange。

主要方法

这个类提供对外的接口非常简洁,一个无参构造函数,两个重载的范型exchange方法:

等待另外一个线程到达此交换点(除非当前线程被中断),将给定的对象x传送给该线程,并且接收该线程的对象。

public V exchange(V x) throws InterruptedException

等待另外一个线程到达此交换点(除非当前线程被中断,或者超出了指定的等待时间),将指定的对象x传送给该线程,同时接收该线程的对象。

public V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException

Exchanger的应用场景

Exchanger可以用于遗传算法,遗传算法里需要选出两个人作为交配对象,这时候会交换两人的数据,并使用交叉规则得出2个交配结果。

只要用于两个线程之间交换数据。

如果两个线程有一个没有到达exchange方法,则会一直等待,如果担心有特殊情况发生,避免一直等待,可以使用exchange(V x, long timeout, TimeUnit unit)设置最大等待时长。

案例

比如生活中两个人,一个人有零食,另一个人有钱,他们两个想等价交换,对好口号在某个地方相见,一个人先到了之后,必须等另一个人带着需要的东西来了之后,才能开始交换。

public class ExchangerTest {

    public static void main(String[] args) {
        Exchanger exchanger = new Exchanger();
        ExecutorService service = Executors.newCachedThreadPool();
        //线程1 拿着零食来交换
        service.submit(() -> {
            String data1 = "零食";
            System.out.println("线程" + Thread.currentThread().getName() +
                    "正在把数据 " + data1 + " 换出去");
            String data2 = null;
            try {
                System.out.println("正在交换等待10s");
                Thread.sleep((long) Math.random() * 10000);
                //开始交换数
                data2 = (String) exchanger.exchange(data1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程 " + Thread.currentThread().getName() +
                    "换回的数据为 " + data2);

        });

        //线程2 拿着钱来交换
        service.submit(() -> {
            String data1 = "钱";
            System.out.println("线程" + Thread.currentThread().getName() +
                    "正在把数据 " + data1 + " 交换出去");
            String data2 = null;
            try {
                System.out.println("正在交换等待10s");
                Thread.sleep((long) (Math.random() * 10000));
                //开始交换数
                data2 = (String) exchanger.exchange(data1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("线程 " + Thread.currentThread().getName() +
                    "交换回来的数据是: " + data2);

        });

        service.shutdown();

    }
}

输出

线程pool-1-thread-1正在把数据 零食 换出去
正在交换等待10s
线程pool-1-thread-2正在把数据 钱 交换出去
正在交换等待10s
线程 pool-1-thread-2交换回来的数据是: 零食
线程 pool-1-thread-1换回的数据为 钱