【并发设计模式】聊聊 基于Copy-on-Write模式下的CopyOnWriteArrayList

news2024/11/16 21:52:16

在并发编程领域,其实除了使用上一篇中的属性不可变。还有一种方式那就是针对读多写少的场景下。我们可以读不加锁,只针对于写操作进行加锁。本质上就是读写复制。读的直接读取,写的使用写一份数据的拷贝数据,然后进行写入。在将新的数据指到原来的引用上。Java中的CopyOnWriteArrayList、CopyOnWriteArraySet 都是按照COW,写时复制实现的。

    public E set(int index, E element) {
        // 加锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            E oldValue = get(elements, index);

            if (oldValue != element) {
                int len = elements.length;
                //复制一个数组
                Object[] newElements = Arrays.copyOf(elements, len);
                newElements[index] = element;
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);
            }
            return oldValue;
        } finally {
             // 解锁
            lock.unlock();
        }
    }

在这里插入图片描述

Copy On Write模式

那么COW在别的领域又没有对应的应用,
其实在类Linux中,操作系统创建进程的API是fork() , 传统的fork() 会创建一个父进程的完整副本,这样暂用的地址空间就比较大,并且很耗时。linux更加聪明,那就是fork()子进程的时候,不复制整个进程的地址空间,而是让父子进程共享同一个地址空间,只用在父进程或者子进程需要写入的是才会复制地址空间,父子空间在进行隔离。

最经典的领域其实还是函数式编程领域中,通过将数据拷贝一份进行处理,然后返回结果。
COW模式的缺点是可能对于空间上比较浪费的,毕竟需要使用两倍以上的空间,是一种读多写少场景下使用。空间换时间的一种取舍。

实际应用

在实际的RPC中,客户端都是按照路由表进行查询对应服务的列表,比如A服务对应三台实例,就会将请求分发给对应的服务,按照一定的负载均衡策略。而这类进行一般来说其实都是读多写少。处分出现系统故障,恢复服务下线才会出现问题。

我们按照Map.key为服务名,value使用CopyOnWriteArraySet保存。

public class RouterTables {

    private static HashMap<String,CopyOnWriteArraySet<Router>> cr = new HashMap<>();

    static {
        CopyOnWriteArraySet<Router> userApiRouters = new CopyOnWriteArraySet<>();
        userApiRouters.add(new Router("192.1.1.1","8080","online"));
        userApiRouters.add(new Router("192.1.1.2","8080","online"));
        userApiRouters.add(new Router("192.1.1.3","8080","faild"));

        CopyOnWriteArraySet<Router> accountApiRouters = new CopyOnWriteArraySet<>();
        accountApiRouters.add(new Router("192.1.1.1","8080","online"));
        accountApiRouters.add(new Router("192.1.1.2","8080","online"));
        accountApiRouters.add(new Router("192.1.1.3","8080","faild"));

        cr.put("api.user",userApiRouters);
        cr.put("api.account",accountApiRouters);
    }

    public static void addRouter(String apiServiceName,String ip,String port,String serverStatus) {
        if (!cr.containsKey(apiServiceName)) {
            CopyOnWriteArraySet<Router> accountApiRouters = new CopyOnWriteArraySet<>();
            accountApiRouters.add(new Router(ip,port,serverStatus));
            cr.put(apiServiceName,accountApiRouters);
        } else {
            CopyOnWriteArraySet<Router> routers = cr.get(apiServiceName);
            if (routers.contains(new Router(ip,port,serverStatus))) {
                return;
            } else {
                routers.add(new Router(ip,port,serverStatus));
            }
        }
    }

    public static Map<String,CopyOnWriteArraySet<Router>> findRouterInfoByApiName (String apiServiceName) {
        return (Map<String, CopyOnWriteArraySet<Router>>) cr.get(apiServiceName);
    }

    public static void deleteRouterInfoByApiName (String apiServiceName) {
        if (cr.containsKey(apiServiceName)) {
            cr.remove(apiServiceName);
        }
    }

    public static void prinltnAllInfo() {
        cr.forEach((s, routers) -> System.out.println(s +"\t"+ routers));
    }

}

具体效果就是如下:

api.order	[Router{ip='192.1.1.1', port='8080', isOnline='online'}]
api.account	[Router{ip='192.1.1.1', port='8080', isOnline='online'}, Router{ip='192.1.1.2', port='8080', isOnline='online'}, Router{ip='192.1.1.3', port='8080', isOnline='faild'}]

总结

我们知道ArrayList是并发不安全的容器,如果需要在并发中使用数组集合,并且是读多写少的场景下,就非常推荐使用CopyOnWriteArrayList.
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1339099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java (spring-boot)的超市管理系统

一、项目介绍 超市管理系统对商品日常维护、售卖、商品类别、存储记录、库存维护等功能的统计及整理。系统设计了系统管理员&#xff0c;销售人员&#xff0c;仓库管理员多个角色。通过多角色、多功能的使用&#xff0c;可以方便地查询商品的库存值、是否临期、是否库存紧张&am…

ubuntu20 安装缺失的字体

在/usr/share/fonts创建文件夹winfonts sudo mkdir winfonts 下载缺失的字体后&#xff0c;复制命令到对应的文件夹。 刷新字体库 sudo mkfontscale sudo mkfontdir sudo fc-cache

可视化远程监控EasyCVR及AI识别技术在种植养殖基地/果园场景中的应用建设

一、背景与需求 种植园、果园一般场地面积较大&#xff0c;看守人员较少&#xff0c;财产安全成为了关注的重点。传统靠人力监管的方式效率低下&#xff0c;管理也较为片面且人力投入大&#xff0c;那么如何实现少人化、智能化监管&#xff0c;助力果园安全监控、守护园区安全…

怎么用Facebook找客户?Facebook开发客户攻略分享

跨境人最了解的电商平台之一就是Facebook了&#xff0c;说到Facebook&#xff0c;它拥有超过20亿的活跃用户&#xff0c;所以你可以在这个平台上面找到更多的潜在客户。今天的文章就主要分享用Facebook开发客户的方法&#xff0c;全是干货&#xff0c;建议收藏&#xff01; 一、…

IPv4 VS IPv6代理全解,跨境电商代理IP选哪种?

IP&#xff08;互联网协议&#xff09;被网站用来收集用户位置信息。当今最流行的两种互联网协议是 IPv4 和 IPv6。 在我们选择IP代理的过程中可以看到IPv4、IPv6两种类型&#xff0c;他们有何区别&#xff1f;如何选择&#xff1f;下面为大家讲解&#xff01; 在这篇文章中&a…

全面理解Stable Diffusion采样器

全面理解Stable Diffusion采样器 原文&#xff1a;Stable Diffusion Samplers: A Comprehensive Guide 在 AUTOMATIC1111 的 SD webui 中&#xff0c;有许多采样器&#xff08;sampler&#xff09;&#xff0c;如 Euler a&#xff0c;Heun&#xff0c;DDIM&#xff0c;… 什么是…

.NET CORE 无法调试 当前不会命中断点

多个项目直接可以设置项目的属性->生成->输出的配置文件输出地址 然后路径统一输入该项目的bib/debug/.netcorex.x就可以了

Pandas教程(二)—— 不同格式的数据读取

前言&#xff1a;几种常用数据格式的介绍 csv文件 1. 逗号分隔值文件&#xff0c;以纯文本形式&#xff08;记事本&#xff09;存储表格数据 2. 它是一种平面文件&#xff1a;即只存储数据和文字&#xff0c;不能存储公式、图表等 3. 更适合存储大数据&#xff0c;一般用来批…

如何解决msvcr100.dll丢失问题,深度解析5种靠谱的方法

在计算机的世界里&#xff0c;我们常常会遇到一些看似微不足道的问题&#xff0c;但它们却可能引发一系列的困扰。其中之一就是“msvcr100.dll丢失”。这个问题可能会导致某些程序无法正常运行。本文将介绍5种解决msvcr100.dll丢失问题的方法。 msvcr100.dll是什么 msvcr100.d…

NXP S32K358 davinci cfg can驱动配置

NXP S32K358一共有8路can&#xff0c;都支持Can FD和Classical Can。其中FlexCan0-2是增强型CAN&#xff0c;支持8byte的mailbox 96个。FlexCan3-7支持8byte的mailbox 64个。 1.增强型Can和普通Can波特率采样点设置区别 在NXP S32K358中增强CAN的波特率采样点的寄存器和普通C…

新手为什么跟着大型机构交易?fpmarkets总结理由

正所谓方向不对努力白费&#xff0c;这也就是为什么fpmarkets建议新手在刚开始的时候&#xff0c;跟着大型机构进行交易。 这些大型机构包括中央银行、巨额对冲基金、投资和保险公司等等&#xff0c;首先fpmarkets认为这些大型机构的交易量巨大&#xff0c;能够影响市场的走势。…

2023年12月27日学习记录_加入噪声

目录 1、今日计划学习内容2、今日学习内容1、add noise to audio clipssignal to noise ratio(SNR)加入 additive white gaussian noise(AWGN)加入 real world noises 2、使用kaggel上的一个小demo&#xff1a;CNN模型运行时出现的问题调整采样率时出现bug 3、明确90dB下能否声…

hadoop hive spark flink 安装

下载地址 Index of /dist ubuntu安装hadoop集群 准备 IP地址主机名称192.168.1.21node1192.168.1.22node2192.168.1.23node3 上传 hadoop-3.3.5.tar.gz、jdk-8u391-linux-x64.tar.gz JDK环境 node1、node2、node3三个节点 解压 tar -zxvf jdk-8u391-linux-x64.tar.gz…

Git系统有哪些优势

在现在的这个软件开发领域&#xff0c;版本控制是一项非常重要的工作。Git作为比较流行的分布式版本控制系统&#xff0c;他有着独特的优势成为了很多开发者们的首选。那Git系统都有哪些优势呢&#xff0c;下面我以自己的理解简单的介绍一下。 分布式版本控制的优势 Git用的是…

003、一起来玩猜数游戏吧!

1. 上篇补充 在项目 hello_world 中&#xff0c;有一些文件。这里提一下每个文件的用途&#xff0c;了解一下即可&#xff0c;暂时不用深究&#xff0c;后面用到会详细讨论。 1. src &#xff1a;这个文件夹里主要用于存放源代码文件。Rust 项目的源代码文件通常以 .rs 为后缀&…

给typora更换字体

给typora更换字体 1.字体推荐(程序员) JetBrains MonoFira CodeCascadia Code 如果你不知道用哪个&#xff0c;把所有字体都装上。 2.安装字体 以 JetBrainsMono-1.0.3 为例&#xff0c;打开 ttf 文件夹&#xff0c;选择字体&#xff0c;右键 安装 3.设置typora的字体 文…

three.js 模型 居中

物体不居中 模型的几何中心位置不对&#xff0c; 设置偏离物体实际几何中心&#xff0c;当设置position&#xff08;0,0,0&#xff09;时就会出现偏离。 解决方案 此处有两种解决方案 建模师处理模型&#xff0c;将模型的几何中心移动到&#xff08;0&#xff0c; 0&#…

【Linux】进程查看|fork函数|进程状态

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&am…

Java日期工具类时间校验

Java日期工具类时间校验 嘚吧嘚正则表达式版本一版本二版本三 SimpleDateFormat工具类 嘚吧嘚 时间校验这个问题&#xff0c;我在网上找了很多资料&#xff0c;有用正则表达式的、有用格式工具类的。&#x1f928; 其实都能实现时间校验&#xff0c;既然两种方式都能实现&…

Vue3-25-路由-路由的基本使用

对路由的理解 路由 &#xff1a; 就是前端对页面路径的拦截&#xff0c;根据不同的路径渲染不同的组件&#xff0c; 从而实现单页应用中的页面局部刷新的功能。安装路由依赖 根据使用的不同的包管理工具采用不同的命令&#xff0c; 常见的三种包管理工具和对应的命令如下&…