• 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();
                    }
                }
                
            }
        }
    }
  • 相关阅读:
    windows 安装 nodejs指定版本
    Xshell通过ssh登录远程服务器(秘钥)
    CentOS7 防火墙操作
    Linux系统MySQL开启远程连接
    PHP 下载图片文件并压缩文件成zip
    thinkphp 中更新数据字段,同时某字段值++操作(报错TP5.1不支持的数据表达式:[exp]的解决办法)
    layui的loading加载中
    Linux下面安装swoole
    windows 下cmd命令删除文件或者文件夹
    PHP 删除某目录下的全部文件
  • 原文地址:https://www.cnblogs.com/dengzy/p/5817474.html
Copyright © 2020-2023  润新知