zoukankan      html  css  js  c++  java
  • [笔记][Java7并发编程实战手冊]3.8 并发任务间的数据交换Exchanger

    [笔记][Java7并发编程实战手冊]系列文件夹


    简单介绍

      Exchanger 是一个同步辅助类。用于两个并发线程之间在一个同步点进行数据交换。
      同意两个线程在某一个点进行数据交换。


    本章exchanger 使用心得总结

    1. 两个线程必须使用同一个Exchanger对象,且仅仅能是两个线程间的数据交换
    2. exchanger.exchange(v)的时候,当前线程会被堵塞,直到还有一个线程运行该方法,同一时候完成数据的交换
    3. 相似这样的数据交换的,生产者线程一定要先生产数据。再交换数据,消费者线程一定要先交换数据,再消费数据,否则会出现少消费数据的现象

    演示样例

    场景描写叙述:一对一的 生产者和消费者。生产者每次生产5个商品,然后消费者把空的商品容器和生产者交换。

    /**
     * Created by zhuqiang on 2015/8/23 0023.
     */
    public class Client {
        public static void main(String[] args) {
            Exchanger<ArrayList<String>> exchanger = new Exchanger<ArrayList<String>>();
    
            new Thread(new Producer(exchanger)).start();
            new Thread(new Consumer(exchanger)).start();
    
        }
    }
    
    // 生产者
    class Producer implements Runnable {
        private ArrayList<String> goods = new ArrayList<String>();  //商品容器
        private Exchanger<ArrayList<String>> exchanger = new Exchanger<ArrayList<String>>();
    
        public Producer(Exchanger<ArrayList<String>> exchanger) {
            this.exchanger = exchanger;
        }
    
        @Override
        public void run() {
            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 {
                    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>>();
    
        public Consumer(Exchanger<ArrayList<String>> exchanger) {
            this.exchanger = exchanger;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 3; i++) {  //消费3次
                try {
                    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();
                }
            }
        }
    }

    某一次运行结果:

    ------------------------生产者生产第 0次
    生产了商品:727
    生产了商品:671
    生产了商品:345
    生产者:数据交换完成:获得交换的商品容器大小:0
    ------------------------生产者生产第 1次
    生产了商品:67
    生产了商品:466
    生产了商品:207
    消费者:数据交换完成:获得交换的商品容器大小:3
    *********************消费者消费第 0次
    消费了商品:727
    消费了商品:671
    消费了商品:345
    消费者:数据交换完成:获得交换的商品容器大小:3
    生产者:数据交换完成:获得交换的商品容器大小:0
    ------------------------生产者生产第 2次
    *********************消费者消费第 1次
    消费了商品:67
    消费了商品:466
    消费了商品:207
    生产了商品:38
    生产了商品:355
    生产了商品:24
    生产者:数据交换完成:获得交换的商品容器大小:0
    消费者:数据交换完成:获得交换的商品容器大小:3
    *********************消费者消费第 2次
    消费了商品:38
    消费了商品:355
    消费了商品:24

    结果说明
    看上面的结果,能够发现两个线程是并行运行的,仅仅有在交换的时候,交换数据同步点。


    是不是认为看着不明所以。这样看
    ————————生产者生产第 0次
    生产了商品:727

    第0次生产商品是 727。
    ***********消费者消费第 0次
    消费了商品:727

    第0次消费的也是727, 这就说明了。两个线程之间交换数据是我们想要的结果。

    假如:我们把 以下的运行顺序调换下,让consumer在前。结果你发现还是先生产后消费。

    这个是为什么呢?

        new Thread(new Producer(exchanger)).start();
        new Thread(new Consumer(exchanger)).start();

    是由于:
    1. 从java内存模型角度来说。上面两行代码没有数据依赖性(在实际运行的时候他们的顺序不一定是谁先谁后)
    2. 原因就出如今exchanger.exchange(v)方法。就算是消费者先运行,细致看代码。消费者会先运行exchanger.exchange(v)方法。假设之前没有线程运行该方法,那么消费者则会休眠等待生产者运行该方法。

  • 相关阅读:
    还有为window.close()方法弹出的询问窗口烦?
    ValidateTextBox发布绝对实用
    面向对象设计的11个原则
    关于建立控件、组件开发团队,有兴趣的网友请留言
    存储过程和触发器要使用链接服务器时要注意的一点
    “这块布的艺术成分都几高唧!”“有几高啊?”“三、四层楼那么高啦。”
    有没有人用过负离子发生器?
    摇滚你的页面。Free:RockUControl控件发布,开源:RevealTransitionImage
    控件开发团队序言及加入说明
    一些平时能用到的CSS效果(ZT+YC)
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/7304994.html
Copyright © 2011-2022 走看看