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

在并发编程领域,其实除了使用上一篇中的属性不可变。还有一种方式那就是针对读多写少的场景下。我们可以读不加锁,只针对于写操作进行加锁。本质上就是读写复制。读的直接读取,写的使用写一份数据的拷贝数据,然后进行写入。在将新的数据指到原来的引用上。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 semanticssetArray(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.mzph.cn/news/577483.shtml

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

相关文章

CSS5 | CSS滑动门左扇与右扇图片重叠问题解决

本文中所使用的滑动门背景图片是自己用微软相册手工切的&#xff0c;没用ps&#xff0c;所以凑乎看吧 首先放出一张目标效果也是最终完成图 下面说问题 CSS推拉门原理 按原理来说&#xff0c;就是两个行内块前后站一行&#xff0c;然后前面的a标签和span标签分别是推拉门素材…

添加与搜索单词 - 数据结构设计[中等]

一、题目 请你设计一个数据结构&#xff0c;支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。 实现词典类WordDictionary&#xff1a; 1、ordDictionary()初始化词典对象 2、void addWord(word)将word添加到数据结构中&#xff0c;之后可以对它进行匹配 3、b…

对递归、循环和迭代的理解

递归、循环和迭代都是编程和算法中非常重要的知识&#xff0c;以下是本人对他们的理解&#xff0c;若有不对&#xff0c;还希望大家可以批评指正&#xff01; 递归&#xff1a;将一个大问题分解成多个相似的小问题&#xff0c;再将小问题分成更小的相似问题&#xff0c;然后逐个…

解密 Java ForEach 提前终止问题

目录 前言&#xff1a;场景复现分析与解决方案解决方案详解总结 前言&#xff1a; 你是否曾在使用 Java 8 的 forEach 迭代集合时遇到过提前终止循环的问题&#xff1f;在这篇博客中&#xff0c;我们将深入探讨这一问题&#xff0c;并提供多种解决方案。通过场景复现、分析源码…

Arduino驱动TMF8701 ToF激光测距传感器(距离传感器)

目录 1、传感器特性 2、硬件原理图 3、控制器和传感器连线图 4、驱动程序 <

TCP 三次握手:四次挥手

TCP 三次握手/四次挥手 TCP 在传输之前会进行三次沟通&#xff0c;一般称为“三次握手”&#xff0c;传完数据断开的时候要进行四次沟通&#xff0c;一般称为“四次挥手”。 数据包说明 源端口号&#xff08; 16 位&#xff09;&#xff1a;它&#xff08;连同源主机 IP 地址…

生成二维码,条形码,带数字,输出到文件

生成二维码和条形码 依赖 <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.4.1</version></dependency><dependency><groupId>com.google.zxing</groupId><a…

验证码服务使用指南

验证码服务使用指南 1 部署验证码服务 1.1 基础环境 Java 1.8 Maven3.3.9 1.2 安装Redis 参考“Redis安装指南” 1.3 部署验证码服务 1.3.1 下载源码 使用git从远程下载验证码服务代码(开源)。 1.3.2 使用idea打开项目 使用idea打开上一步下载的sailing目录&#xf…

优维产品最佳实践第20期:控制台全链路监控

之前我们会觉得cmdb自动发现没有上报很难排查&#xff0c;弄不清楚数据的上报链路&#xff1b;监控指标的数据断点很难定位&#xff0c;flink对现场来说是一个黑盒子&#xff1b;apm数据更新不及时到底是上报异常还是入库失败呢&#xff1f; 现在控制台集成了对数据链路的监控…

超声系统前端理论与模拟仿真-续

作者&#xff1a;蒋志强 本人同意他人对我的文章引用&#xff0c;但请在引用时注明出处&#xff0c;谢谢&#xff0e;作者&#xff1a;蒋志强 前言 近期整理了一下彩超前端及波束合成相关的内容&#xff0c;很早以前已经有过一次&#xff0c;这次把其它的内容总结一下&#xf…

【数据结构】什么是二叉树?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;二叉树的定义 &#x1f4cc;二叉树的特点 &#x1f4cc;特殊二叉树 &#x1f4cc;二叉树的性质 &#x1f4cc;二叉树的存储结构 &#x1f4cc;二叉树…

【Vue3+TypeScript】快速上手_代码

目录 001_写一个APP组件 002_一个简单的效果 003_setup概述 004_setup的返回值 005_setup与Options API的关系 006_setup语法糖 007_ref创建_基本类型的响应式数据 008_reactive创建_对象类型的响应式数据 009_ref创建_对象类型的响应式数据 010_ref对比reactive 01…

【golang】init()函数是什么时候执行的?

init() Go中的main()函数是程序执行的入口&#xff0c;main()函数执行完后&#xff0c;程序就等于结束了。Go中还有一个函数是在main()函数前执行&#xff0c;可以实现包级别的初始化操作–init()。 怎么执行的&#xff1f; Go程序初始化先于main函数&#xff0c;由runtime初…

(2023|CVPR,Corgi,偏移扩散,参数高斯分布,弥合差距)用于文本到图像生成的偏移扩散

Shifted Diffusion for Text-to-image Generation 公众&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 方法 2.1 偏移扩散 3. 实验 3.1 无监督文本到图像生成 3.2 无…

三相电机转差率为负值的情形

1.电机开始发电的特征 注意&#xff0c;电机因为有输入频率对原始旋转磁场的影响&#xff0c;在正常工作时&#xff0c;应该处于稳态&#xff0c;因为旋转磁场决定了这个系统的运转方向和运转的大致频率区间。它会处于力矩平衡态。但是&#xff0c;如果&#xff0c;此时电机处…

网络安全保障领域

计算机与信息系统安全---最主要领域 云计算安全 IaaS、PasS、SaaS(裸机&#xff0c;装好软件的电脑&#xff0c;装好应用的电脑) 存在风险&#xff1a;开源工具、优先访问权、管理权限、数据处、数据隔离、数据恢复、调查支持、长期发展风险 云计算安全关键技术&#xff1a;可信…

【深度解析C++之初始化列表】

系列文章目录 欢迎大家订阅我的《计算机底层原理》、《深度解析C》系列专栏、我会持续为大家输出优质文章&#xff0c;能够帮助到大家就是对我最大的鼓励&#xff01;&#x1f60a; 目录 系列文章目录 前言 一、什么是初始化列表 1.语法结构 2.为什么要使用初始化列表 1.…

LeetCode 2974. 最小数字游戏

你有一个下标从 0 开始、长度为 偶数 的整数数组 nums &#xff0c;同时还有一个空数组 arr 。Alice 和 Bob 决定玩一个游戏&#xff0c;游戏中每一轮 Alice 和 Bob 都会各自执行一次操作。游戏规则如下&#xff1a; 每一轮&#xff0c;Alice 先从 nums 中移除一个 最小 元素&…

Vue-Pinina基本教程

前言 官网地址&#xff1a;Pinia | The intuitive store for Vue.js (vuejs.org) 看以下内容&#xff0c;需要有vuex的基础&#xff0c;下面很多概念会直接省略&#xff0c;比如state、actions、getters用处含义等 1、什么是Pinina Pinia 是 Vue 的存储库&#xff0c;它允许您跨…

AI一叶知秋:从目标检测部署浅谈人工智能发展

笔者写这篇文章也有讨巧之嫌&#xff0c;仅以个人视角分享一些看法&#xff0c;主要从实践部署来谈谈近两年来计算机视觉模型的变化&#xff0c;不过AI是一个宏大的话题&#xff0c;每个人定义的人工智能就不一样&#xff0c;我们先来探讨一下何为人工智能。百度百科中是这样定…