`
747017186
  • 浏览: 317456 次
社区版块
存档分类
最新评论

java线程之Exchanger

 
阅读更多

Exchanger的工作原理及实例

1.实现原理        

          Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据, 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。因此使用Exchanger的重点是成对的线程使用exchange()方法,当有一对线程达到了同步点,就会进行交换数据。因此该工具类的线程对象是成对的

       Exchanger类提供了两个方法,String exchange(V x):用于交换,启动交换并等待另一个线程调用exchange;String exchange(V x,long timeout,TimeUnit unit):用于交换,启动交换并等待另一个线程调用exchange,并且设置最大等待时间,当等待时间超过timeout便停止等待。

2.实例讲解

        通过以上的原理,可以知道使用Exchanger类的核心便是exchange()方法的使用,接下来通过一个例子来使的该工具类的用途更加清晰。该例子主要讲解的是前段时间NBA交易截止日的交易。

  1.  
    package concurrent;
  2.  
    import java.util.concurrent.Exchanger;
  3.  
    import java.util.concurrent.ExecutorService;
  4.  
    import java.util.concurrent.Executors;
  5.  
    import java.util.*;
  6.  
    public class ExchangerDemo {
  7.  
     
  8.  
    public static void main(String[] args) {
  9.  
    ExecutorService executor = Executors.newCachedThreadPool();
  10.  
     
  11.  
    final Exchanger exchanger = new Exchanger();
  12.  
    executor.execute(new Runnable() {
  13.  
    String data1 = "克拉克森,小拉里南斯";
  14.  
     
  15.  
     
  16.  
    @Override
  17.  
    public void run() {
  18.  
    nbaTrade(data1, exchanger);
  19.  
    }
  20.  
    });
  21.  
     
  22.  
     
  23.  
    executor.execute(new Runnable() {
  24.  
    String data1 = "格里芬";
  25.  
     
  26.  
    @Override
  27.  
    public void run() {
  28.  
    nbaTrade(data1, exchanger);
  29.  
    }
  30.  
    });
  31.  
     
  32.  
    executor.execute(new Runnable() {
  33.  
    String data1 = "哈里斯";
  34.  
     
  35.  
    @Override
  36.  
    public void run() {
  37.  
    nbaTrade(data1, exchanger);
  38.  
    }
  39.  
    });
  40.  
     
  41.  
    executor.execute(new Runnable() {
  42.  
    String data1 = "以赛亚托马斯,弗莱";
  43.  
     
  44.  
    @Override
  45.  
    public void run() {
  46.  
    nbaTrade(data1, exchanger);
  47.  
    }
  48.  
    });
  49.  
     
  50.  
    executor.shutdown();
  51.  
    }
  52.  
     
  53.  
    private static void nbaTrade(String data1, Exchanger exchanger) {
  54.  
    try {
  55.  
    System.out.println(Thread.currentThread().getName() + "在交易截止之前把 " + data1 + " 交易出去");
  56.  
    Thread.sleep((long) (Math.random() * 1000));
  57.  
     
  58.  
    String data2 = (String) exchanger.exchange(data1);
  59.  
    System.out.println(Thread.currentThread().getName() + "交易得到" + data2);
  60.  
    } catch (InterruptedException e) {
  61.  
    e.printStackTrace();
  62.  
    }
  63.  
    }
  64.  
    }

运行程序,得到如下结果:

  1.  
    pool-1-thread-1在交易截止之前把 克拉克森,小拉里南斯 交易出去
  2.  
    pool-1-thread-2在交易截止之前把 格里芬 交易出去
  3.  
    pool-1-thread-3在交易截止之前把 哈里斯 交易出去
  4.  
    pool-1-thread-4在交易截止之前把 以赛亚托马斯,弗莱 交易出去
  5.  
    pool-1-thread-2交易得到哈里斯
  6.  
    pool-1-thread-3交易得到格里芬
  7.  
    pool-1-thread-4交易得到克拉克森,小拉里南斯
  8.  
    pool-1-thread-1交易得到以赛亚托马斯,弗莱

        以上例子可以看出两个都调用exchange()方法的线程会进行交换数据。接下来假设线程数目只有奇数个,观察情况:

如以下代码,将第四个线程注释掉。

  1.  
    package concurrent;
  2.  
    import java.util.concurrent.Exchanger;
  3.  
    import java.util.concurrent.ExecutorService;
  4.  
    import java.util.concurrent.Executors;
  5.  
    import java.util.*;
  6.  
    public class ExchangerDemo {
  7.  
     
  8.  
    public static void main(String[] args) {
  9.  
    ExecutorService executor = Executors.newCachedThreadPool();
  10.  
     
  11.  
    final Exchanger exchanger = new Exchanger();
  12.  
    executor.execute(new Runnable() {
  13.  
    String data1 = "克拉克森,小拉里南斯";
  14.  
     
  15.  
     
  16.  
    @Override
  17.  
    public void run() {
  18.  
    nbaTrade(data1, exchanger);
  19.  
    }
  20.  
    });
  21.  
     
  22.  
     
  23.  
    executor.execute(new Runnable() {
  24.  
    String data1 = "格里芬";
  25.  
     
  26.  
    @Override
  27.  
    public void run() {
  28.  
    nbaTrade(data1, exchanger);
  29.  
    }
  30.  
    });
  31.  
     
  32.  
    executor.execute(new Runnable() {
  33.  
    String data1 = "哈里斯";
  34.  
     
  35.  
    @Override
  36.  
    public void run() {
  37.  
    nbaTrade(data1, exchanger);
  38.  
    }
  39.  
    });
  40.  
     
  41.  
    // executor.execute(new Runnable() {
  42.  
    // String data1 = "以赛亚托马斯,弗莱";
  43.  
    //
  44.  
    // @Override
  45.  
    // public void run() {
  46.  
    // nbaTrade(data1, exchanger);
  47.  
    // }
  48.  
    // });
  49.  
     
  50.  
    executor.shutdown();
  51.  
    }
  52.  
     
  53.  
    private static void nbaTrade(String data1, Exchanger exchanger) {
  54.  
    try {
  55.  
    System.out.println(Thread.currentThread().getName() + "在交易截止之前把 " + data1 + " 交易出去");
  56.  
    Thread.sleep((long) (Math.random() * 1000));
  57.  
     
  58.  
    String data2 = (String) exchanger.exchange(data1);
  59.  
    System.out.println(Thread.currentThread().getName() + "交易得到" + data2);
  60.  
    } catch (InterruptedException e) {
  61.  
    e.printStackTrace();
  62.  
    }
  63.  
    }
  64.  
    }

运行程序,得到如下结果:

  1.  
    pool-1-thread-1在交易截止之前把 克拉克森,小拉里南斯 交易出去
  2.  
    pool-1-thread-2在交易截止之前把 格里芬 交易出去
  3.  
    pool-1-thread-3在交易截止之前把 哈里斯 交易出去
  4.  
    pool-1-thread-3交易得到格里芬
  5.  
    pool-1-thread-2交易得到哈里斯

        由结果可知,线程2和线程3进行了交换数据,而线程1一直等待与它交换数据的线程调用exchange,但是只有3个线程,所以会一直等待。

        因此,当两个线程之间出现数据交换的情况,可以使用Exchanger工具类实现数据交换。注意exchange方法的含义,以及触发数据交换的条件。

 

下面看代码例子:

package thread.exchanger;

import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExchangerTest {
	public static void main(String[] args) {
		ExecutorService pool = Executors.newCachedThreadPool();//线程缓存池
		final Exchanger<String> exchanger = new Exchanger<String>();//用于一对线程的交换
		
		pool.execute(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep((long)(Math.random()*10000));
					String data1 = "白粉";
					System.out.println("线程"+Thread.currentThread().getName()+"已经到达交换地点,准备拿"+data1+"交换!");
					data1 = exchanger.exchange(data1);//进行交换返回交换后的物品
					System.out.println("线程"+Thread.currentThread().getName()+"交换成功,拿到"+data1);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		
		pool.execute(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep((long)(Math.random()*10000));
					String data2 = "钱";
					System.out.println("线程"+Thread.currentThread().getName()+"已经到达交换地点,准备拿"+data2+"交换!");
					data2 = exchanger.exchange(data2);//进行交换返回交换后的物品
					System.out.println("线程"+Thread.currentThread().getName()+"交换成功,拿到"+data2);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		
		pool.shutdown();
	}
}



  

注意:exchanger只能用于一对或者一组线程的交换。交换的线程不能为奇数,否则会出现死锁等待。

 

 

 

 

  • 大小: 7.5 KB
分享到:
评论

相关推荐

    Java编程线程同步工具Exchanger的使用实例解析

    主要介绍了Java编程线程同步工具Exchanger的使用实例解析,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下

    java并发Exchanger的使用

    Exchanger是java 5引入的并发类,Exchanger顾名思义就是用来做交换的。这里主要是两个线程之间交换持有的对象。当Exchanger在一个线程中调用exchange方法之后,会等待另外的线程调用同样的exchange方法。 两个线程都...

    Java多线程编程之使用Exchanger数据交换实例

    主要介绍了Java多线程编程之使用Exchanger数据交换实例,本文直接给出实例代码,需要的朋友可以参考下

    Java:Exchanger类的作用.docx

    java.util.concurrent包中的Exchanger类可用于两个线程之间交换信息。可简单地将Exchanger对象理解为一个包含两个格子的容器,通过exchanger方法可以向两个格子中填充信息。当两个格子中的均被填充时,该对象会自动...

    java线程并发semaphore类示例

    Java 5.0里新加了4个协调线程间进程的同步装置,它们分别是Semaphore, CountDownLatch, CyclicBarrier和Exchanger,本例主要介绍Semaphore,Semaphore是用来管理一个资源池的工具,可以看成是个通行证

    【2018最新最详细】并发多线程教程

    【2018最新最详细】并发多线程教程,课程结构如下 1.并发编程的优缺点 2.线程的状态转换以及基本操作 ...26.大白话说java并发工具类-Semaphore,Exchanger 27.一篇文章,让你彻底弄懂生产者--消费者问题

    java jdk实列宝典 光盘源代码

    12反射 是java程序开发的特征之一,允许java程序对自身进行检查,并能直接操作程序的内部属性; instanceof操作符,instanceof.java; 获取类的信息,ViewClassInfoJrame.java; 动态调用类的方法,CallMetod.java; ...

    Java多线程同步器代码详解

    主要介绍了Java多线程同步器代码详解,文章分别介绍了是CountDownLatch,Semaphore,Barrier和Exchanger以及其相关代码示例,具有一定参考价值,需要的朋友可以了解下。

    Java JDK实例宝典

    18 线程——Exchanger 16. 19 线程——BlockingQueue 第17章 Java与XML 17. 1 用DOM处理XML文档 17. 2 用SAX处理XML文档 17. 3 用XSLT转换XML 17. 4 对象与XML的转换 第18章 Java Mail...

    Java并发编程原理与实战

    从Java字节码的角度看线程安全性问题.mp4 synchronized保证线程安全的原理(理论层面).mp4 synchronized保证线程安全的原理(jvm层面).mp4 单例问题与线程安全性深入解析.mp4 理解自旋锁,死锁与重入锁.mp4 深入...

    Java并发编程(学习笔记).xmind

    Exchanger 这是一种两方栅栏,各方在栅栏位置上交换数据。 应用场景:当两方执行不对称的操作(读和取) 线程池 任务与执行策略之间的隐形耦合 线程饥饿死锁 运行时间较长的任务 ...

    龙果java并发编程完整视频

    第13节从Java字节码的角度看线程安全性问题00:25:43分钟 | 第14节synchronized保证线程安全的原理(理论层面)00:13:59分钟 | 第15节synchronized保证线程安全的原理(jvm层面)00:25:03分钟 | 第16节单例问题与...

    龙果 java并发编程原理实战

    第13节从Java字节码的角度看线程安全性问题00:25:43分钟 | 第14节synchronized保证线程安全的原理(理论层面) 00:13:59分钟 | 第15节synchronized保证线程安全的原理(jvm层面)00:25:03分钟 | 第16节单例问题...

    尚硅谷——java.util.concurrent和工具类

    一、java.util.concurrent体系的主要大板块包含内容 二、Executors 三、Semaphor信号量 四、Exchanger线程交互 五、CyclicBarrier关卡模式 六、CountDownLatch计数器

    Java并发包讲解

    java并发包讲解 可以找我要代码,qq 3341386488 ## 线程安全-并发容器JUC--原理以及分析 1.arrayList --copyonWriteArraylist 优缺点 2.HashSet,TreeSet -- CopyONWriteArraySet,ConcurrentSkipListSet 3....

    JAVA并发编程-2-线程并发工具类

    JAVA并发编程-2-线程并发工具类一、Fork/Join1、分而治之与工作密取2、使用标准范式3、Fork/Join的同步用法4、Fork/Join的异步用法二、CountDownLatch三、CyclicBarrier四、Semaphore信号量五、Exchanger ...

    Java 并发编程原理与实战视频

    第13节从Java字节码的角度看线程安全性问题00:25:43分钟 | 第14节synchronized保证线程安全的原理(理论层面) 00:13:59分钟 | 第15节synchronized保证线程安全的原理(jvm层面)00:25:03分钟 | 第16节单例问题...

    java并发编程

    第13节从Java字节码的角度看线程安全性问题00:25:43分钟 | 第14节sy nchronized保证线程安全的原理(理论层面)00:13:59分钟 | 第15节synchronized保证线程安全的原理(jvm层面)00:25:03分钟 | 第16节单例问题...

Global site tag (gtag.js) - Google Analytics