当前位置: 首页 > news >正文

​Java并发新构件之Exchanger

为什么80%的码农都做不了架构师?>>>   hot3.png

    Exchanger是在两个任务之间交换对象的栅栏。当两个任务进入栅栏时,它们各自拥有一个对象,当它们离开时,它们都拥有对方的对象。Exchanger的典型应用场景是:一个任务在创建对象,而这些对象的生产代价很高,另一个任务在消费这些对象。通过这种方式,可以有更多的对象在被创建的同时被消费。

    为了演示Exchanger类,我们将创建生产者和消费者任务。ExchangerProducer和ExchangerConsumer使用一个List<Fat>作为要求交换的对象,它们都包含一个用于这个List<Fat>的Exchanger。当你调用Exchanger.exchange()方法时,它将阻塞直至对方任务调用它自己的exchange()方法,那时,这两个exchange()方法将同时完成,而List<Fat>被交换:

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class ExchangerProducer implements Runnable {
    private List<Fat> holder;
    private Exchanger<List<Fat>> exchanger;
    public ExchangerProducer(Exchanger<List<Fat>> exchanger, List<Fat> holder) {
        this.exchanger = exchanger;
        this.holder = holder;
    }
    @Override
    public void run() {
        try {
            while(!Thread.interrupted()) {
                //填充列表
                for (int i = 0;i < ExchangerDemo.size; i++) {
                    holder.add(new Fat());
                }
                //等待交换
                holder = exchanger.exchange(holder);
            }
        } catch (InterruptedException e) {
        }
        System.out.println("Producer stopped.");
    }
}

class ExchangerConsumer implements Runnable {
    private List<Fat> holder;
    private Exchanger<List<Fat>> exchanger;
    private volatile Fat value;
    private static int num = 0;
    public ExchangerConsumer(Exchanger<List<Fat>> exchanger, List<Fat> holder) {
        this.exchanger = exchanger;
        this.holder = holder;
    }
    @Override
    public void run() {
        try {
            while(!Thread.interrupted()) {
                //等待交换
                holder = exchanger.exchange(holder);
                //读取列表并移除元素
                for (Fat x : holder) {
                    num++;
                    value = x;
                    //在循环内删除元素,这对于CopyOnWriteArrayList是没有问题的
                    holder.remove(x);
                }
                if (num % 10000 == 0) {
                    System.out.println("Exchanged count=" + num);
                }
            }
        } catch (InterruptedException e) {
            
        }
        System.out.println("Consumer stopped. Final value: " + value);
    }
}

public class ExchangerDemo {
    static int size = 10;
    static int delay = 5; //秒
    public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newCachedThreadPool();
        List<Fat> producerList = new CopyOnWriteArrayList<>();
        List<Fat> consumerList = new CopyOnWriteArrayList<>();
        Exchanger<List<Fat>> exchanger = new Exchanger<>();
        exec.execute(new ExchangerProducer(exchanger, producerList));
        exec.execute(new ExchangerConsumer(exchanger, consumerList));
        TimeUnit.SECONDS.sleep(delay);
        exec.shutdownNow();
    }
}

class Fat {
    private volatile double d;
    private static int counter = 1;
    private final int id = counter++;
    public Fat() {
        //执行一段耗时的操作
        for (int i = 1; i<10000; i++) {
            d += (Math.PI + Math.E) / (double)i;
        }
    }
    public void print() {System.out.println(this);}
    public String toString() {return "Fat id=" + id;}
}

执行结果(可能的结果):

Exchanged count=10000
Exchanged count=20000
Exchanged count=30000
Exchanged count=40000
Exchanged count=50000
Exchanged count=60000
Exchanged count=70000
Exchanged count=80000
Consumer stopped. Final value: Fat id=88300
Producer stopped.

    在main()中,创建了用于两个任务的单一的Exchanger,以及两个用于互换的CopyOnWriteArrayList。这个特定的List变体允许列表在被遍历的时候调用remove()方法,而不会抛出ConcurrentModifiedException异常。ExchangerProducer将填充这个List,然后将这个满列表跟ExchangerConsumer的空列表交换。交换之后,ExchangerProducer可以继续的生产Fat对象,而ExchangerConsumer则开始使用满列表中的对象。因为有了Exchanger,填充一个列表和消费另一个列表便同时发生了。

转载于:https://my.oschina.net/itblog/blog/518920

相关文章:

  • 本地管理员密码解决方案 Local Admin Password Solution (LAPS)
  • 自适应电脑、手机和iPad的网页设计方法
  • 团队博客作业Week4 --- 学霸网站--NABC
  • Effective Java
  • 虚拟机克隆后网络配置
  • 解决 居中 问题
  • 提交(post)xml文件给指定url的2种方法
  • Why NO to: MySQL, Symfony, CakePHP, Smarty, etc.
  • grub引导程序
  • 不使用(a+b)/2这种方式,求两个数的平均值
  • 可以动态添加图片的轮播插件
  • nginx rewrite模块探究与实验
  • SpringMVC(六):Spring 整合quartz作业调度框架
  • ecshop中那些有意思的代码
  • 查看死锁原因 /data/anr/traces.txt
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 《深入 React 技术栈》
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • 0基础学习移动端适配
  • CentOS6 编译安装 redis-3.2.3
  • Docker 笔记(2):Dockerfile
  • js作用域和this的理解
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • supervisor 永不挂掉的进程 安装以及使用
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 聚类分析——Kmeans
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 利用DataURL技术在网页上显示图片
  • 如何用vue打造一个移动端音乐播放器
  • 使用 Docker 部署 Spring Boot项目
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • (1)STL算法之遍历容器
  • (14)Hive调优——合并小文件
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (2)STL算法之元素计数
  • (JS基础)String 类型
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (算法)求1到1亿间的质数或素数
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .bashrc在哪里,alias妙用
  • .describe() python_Python-Win32com-Excel
  • .gitignore文件_Git:.gitignore
  • .net framework 4.0中如何 输出 form 的name属性。
  • .NET HttpWebRequest、WebClient、HttpClient
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NET学习全景图
  • ?php echo ?,?php echo Hello world!;?
  • [2021 蓝帽杯] One Pointer PHP
  • [C++]四种方式求解最大子序列求和问题
  • [CISCN 2019华东南]Web11