并发包中的Exchanger同步工具

一、Exchanger同步工具

可以在对中对元素进行配对和交换的线程的同步点每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象。Exchanger 可能被视为 SynchronousQueue 的双向形式。Exchanger可能在应用程序(比如遗传算法和管道设计)中很有用。


1.1 API

API 描述
V exchange(V x) 等待另一个线程到达此交换点(除非当前线程被中断),然后将给定的对象传送给该线程,并接收该线程的对象
V exchange(V x, long timeout, TimeUnit unit) 等待另一个线程到达此交换点(除非当前线程被中断,或者超出了指定的等待时间),然后将给定的对象传送给该线程,同时接收该线程的对象。

1.2 用法分析

用法示例:以下是重点介绍的一个类,该类使用 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();
   }
  }

内存一致性效果:对于通过Exchanger成功交换对象的每对线程,每个线程中在 exchange()之前的操作 happen-before 从另一线程中相应的 exchange()返回的后续操作。


1.3 案例分析

public class ExchangerTest {

    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        final Exchanger exchanger = new Exchanger();
        service.execute(new Runnable(){
            public void run() {
                try {               

                    String data1 = "zxx";
                    System.out.println("线程" + Thread.currentThread().getName() + 
                    "正在把数据" + data1 +"换出去");
                    Thread.sleep((long)(Math.random()*10000));
                    String data2 = (String)exchanger.exchange(data1);
                    System.out.println("线程" + Thread.currentThread().getName() + 
                    "换回的数据为" + data2);
                }catch(Exception e){

                }
            }   
        });
        service.execute(new Runnable(){
            public void run() {
                try {               

                    String data1 = "lhm";
                    System.out.println("线程" + Thread.currentThread().getName() + 
                    "正在把数据" + data1 +"换出去");
                    Thread.sleep((long)(Math.random()*10000));                  
                    String data2 = (String)exchanger.exchange(data1);
                    System.out.println("线程" + Thread.currentThread().getName() + 
                    "换回的数据为" + data2);
                }catch(Exception e){

                }               
            }   
        });     
    }
}

打印结果

线程pool-1-thread-1正在把数据zxx换出去
线程pool-1-thread-2正在把数据lhm换出去
线程pool-1-thread-2换回的数据为zxx
线程pool-1-thread-1换回的数据为lhm

参考

张孝祥-Java多线程与并发库高级应用

猜你喜欢

转载自blog.csdn.net/qq_31156277/article/details/80516891