thread_Exchanger数据交换

Exchanger 是一个同步辅助类,用于两个并发线程之间在一个同步点进行数据交换。
 允许两个线程在某一个点进行数据交换。
 可以视作双向的同步队列;
 可应用于基因算法、流水线设计等场景

Exchanger提供了 一个同步点 , 在这个同步点,两个线程可以交换数据 。每个线程通过exchange()方法的入口提供数据给另外的线程,并接收其它线程提供的数据,并返回。

public class Exchanger1Test {

    // 场景描述:一对一的 生产者和消费者,生产者每次生产5个商品,然后消费者把空的商品容器和生产者交换。
    // 生产者线程一定要先生产数据,再交换数据,消费者线程一定要先交换数据,再消费数据,否则会出现少消费数据的现象
    // 允许原子性的交换两个(多个)对象,但同时只有一对才会成功
    // exchange方法真的帮一对线程交换了数据;
    // exchange方法真的会阻塞调用方线程直至另一方线程参与交易。
    public static void main(String[] args) {

        // Exchanger可以在两个线程之间交换数据,只能是2个线程,他不支持更多的线程之间互换数据。
        // 两个线程必须使用同一个Exchanger对象,且只能是两个线程间的数据交换
        // 当线程A调用Exchange对象的exchange()方法后,他会陷入阻塞状态,直到线程B也调用了exchange()方法,然后以线程安全的方式交换数据,之后线程A和B继续运行
        Exchanger<ArrayList<String>> exchanger = new Exchanger<ArrayList<String>>();
        ExecutorService exec = Executors.newCachedThreadPool();

        exec.execute(new Producer(exchanger));
        exec.execute(new Consumer(exchanger));
        exec.shutdown();
        try {
            exec.awaitTermination(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // log.error(e, e);
        }
    }
}

// 生产者
class Producer implements Runnable {
    private ArrayList<String> goods = new ArrayList<String>(); // 商品容器
    private Exchanger<ArrayList<String>> exchanger = new Exchanger<ArrayList<String>>();
    //控制交易双方线程的退出
    private static AtomicBoolean isDone = new AtomicBoolean(true);
    public Producer(Exchanger<ArrayList<String>> exchanger) {
        this.exchanger = exchanger;
    }

    @Override
    public void run() {
        while (!Thread.interrupted() &&  isDone.get()) {//

            for (int i = 0; i < 3; i++) { // 生产3次
                System.out.println("------------------------生产者生产第 " + i + "次");
                for (int j = 0; j < 3; j++) { // 每次生产3个商品
                    String e = (long) (Math.random() * 1000) + "";
                    goods.add(e);
                    System.out.println("生产了商品:" + e);
                }
                try {
                    // 生产者线程一定要先生产数据,再交换数据,消费者线程一定要先交换数据,再消费数据
                    // exchanger.exchange(v)的时候,当前线程会被阻塞,直到另一个线程执行该方法,同时完成数据的交换
                    goods = exchanger.exchange(goods); // 交换数据
                    System.out.println("生产者:数据交换完毕:获得交换的商品容器大小:" + goods.size());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

// 消费者
class Consumer implements Runnable {
    private ArrayList<String> goods = new ArrayList<String>(); // 商品容器
    private Exchanger<ArrayList<String>> exchanger = new Exchanger<ArrayList<String>>();
    private static AtomicBoolean isDone = new AtomicBoolean(true);
    public Consumer(Exchanger<ArrayList<String>> exchanger) {
        this.exchanger = exchanger;
    }

    @Override
    public void run() {
        while (!Thread.interrupted() && isDone.get()) {//&& !isDone
            for (int i = 0; i < 3; i++) { // 消费3次
                try {
                    // 生产者线程一定要先生产数据,再交换数据,消费者线程一定要先交换数据,再消费数据
                    // exchanger.exchange(v)的时候,当前线程会被阻塞,直到另一个线程执行该方法,同时完成数据的交换
                    goods = exchanger.exchange(goods); // 交换数据
                    System.out.println("消费者:数据交换完毕:获得交换的商品容器大小:" + goods.size());

                    // 消费商品
                    Iterator<String> it = goods.iterator();
                    if (goods.size() > 0) {
                        System.out.println("*********************消费者消费第 " + i + "次");
                        while (it.hasNext()) {
                            String next = it.next();
                            System.out.println("消费了商品:" + next);
                            it.remove(); // 移除消费了的商品
                        }
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
时间: 2024-08-28 14:13:30

thread_Exchanger数据交换的相关文章

java中的线程协调与线程间的数据交换

Java中提供多种方式协调线程的工作. CountDownLatch:当多个也就是具体的数量等于CountDownLatch初始化参数的时候.线程达到了预期状态或者完成了预期工作时触发事件,其他线程可以等待这个事件来触发自己的后续工作.等待的线程是多个.达到了预期状态的线程会调用CountDownLatch的countDown方法.等待的线程会调用CountDownLatch的await方法. import java.util.concurrent.CountDownLatch; import

JQuery + XML作为前后台数据交换格式实践

JQuery + xml作为前后台数据交换 JQuery提供良好的异步加载接口AJAX,可以局部更新页面数据, http://api.jquery.com/category/ajax/ xml作为一种轻量数据格式,被浏览器js引擎普遍支持,同json格式,但是没有json那么精简. 使用AJAX+xml数据格式来实现动态页面,有以下好处: 1. 松耦合, 页面HTML和数据彻底分离, 即表示层 和 数据层分开, 有利前台样式定制. 不同于以往后台脚本嵌套HTML标签,并输出数据到标签的合适位置,

iOS 中 XML 数据交换格式

     XML 是一种自描述的数据交换格式,但是 XML 的数据交换格式并没有 JSON 来的轻便,但是无可否认的是,XML 的应用范围也是非常广泛的,比如在 ROS(一个开源机器人操作系统)中利用 XML 来描述包的依赖关系等,当然还有很多了.      对于 XML 文档操作包括了"读"与"写",读入 XML 文档并分析的过程称为"解析" XML 文档,"解析" XML 文档在实际开发中是占很大比重的.      读写

Java核心知识点学习----多线程 倒计时记数器CountDownLatch和数据交换的Exchanger

本文将要介绍的内容都是Java5中的新特性,一个是倒计时记数器---CountDownLatch,另一个是用于线程间数据交换的Exchanger. 一.CountDownLatch 1.什么是CountDownLatch? 倒计时计数器,调用CountDownLatch对象的CountDown()方法就将计数器减一,当计数到达0时,则所有等待者或者全部等待者开始执行. 2.如何用? new CountDownLatch(1); 直接new,其构造函数必须传一个int类型的参数,参数的意思是: c

Disruptor——一种可替代有界队列完成并发线程间数据交换的高性能解决方案

本文翻译自LMAX关于Disruptor的论文,同时加上一些自己的理解和标注.Disruptor是一个高效的线程间交换数据的基础组件,它使用栅栏(barrier)+序号(Sequencing)机制协调生产者与消费者,从而避免使用锁和CAS,同时还组合使用预分配内存机制.缓存行机制(cache line).批处理效应(batch effect)来达到高吞吐量和低时延的目标.目前Disruptor版本已经迭代至3.0,本论文是基于Disruptor1.0写就,在新版本中,相对与1.0版本,其核心设计

第三次作业-前端与后台数据交换问题

问题:JS前端取得并解析后台服务器返回的JSON数据方法有哪些? 前一段时间,我在做一个有关美食的Web App,很多商家的店铺信息以及一些用户评论信息等内容需要从后台来获取,如果仅仅只是静态布局的话就太过于死板,但是在进行前端与后端的数据交换时遇到不少问题,如题目JS前端取得并解析后台服务器返回的JSON数据的方法就是问题之一. 在解决这个问题之前,首先需要了解JavaScript eval()函数,eval(string)函数可计算某个字符串,并执行其中JavaScript代码. JS前端取

iOS 中 JSON 数据交换格式

     JSON (JavaScript Object Notation)是一种轻量级的数据交换格式.JSON 的具体教程,可以参见 JSON 中国:http://www.json.org.cn/index.htm ,当然还有 JSON 在线校验格式化工具:http://www.bejson.com/ ,希望深入学习 JSON 可以参考其他教程.JSON 的轻量级是相对于 XML 文档结构而言的,描述项目字符少,所以描述相同的数据所需的字符个数要少,当然传输的速度就会提高而流量也会减少.  

JQuery + JSON作为前后台数据交换格式实践

JQuery + JSON作为前后台数据交换 JQuery提供良好的异步加载接口AJAX,可以局部更新页面数据, http://api.jquery.com/category/ajax/ JSON作为一种轻量数据格式,被浏览器js引擎普遍支持,同xml格式. 使用AJAX+JSON数据格式来实现动态页面,有以下好处: 1. 松耦合, 页面HTML和数据彻底分离, 即表示层 和 数据层分开, 有利前台样式定制. 不同于以往后台脚本嵌套HTML标签,并输出数据到标签的合适位置, 来实现动态页面,表示

MFC拆分窗口及它们之间的数据交换[转]

源代码:http://download.csdn.net/detail/nuptboyzhb/4221531 CSplitterWnd类 CSplitterWnd类提供一个分隔器窗口的功能,分隔器窗口是一个包含有多个窗格的窗口.窗格通常是应用程序特定的由CView派生的对象,但它也可以是具有适当子窗口ID的任何CWnd对象. 一个CSplitterWnd对象通常被嵌入CFrameWnd或CMDIChildWnd父对象.你应按如下步骤创建一个CSplitterWnd对象 1.在父框架中嵌入一个CS