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

【并发设计模式】聊聊 基于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.lryc.cn/news/268466.html

相关文章:

  • OpenCV中使用Mask R-CNN实现图像分割的原理与技术实现方案
  • 论文阅读《Rethinking Efficient Lane Detection via Curve Modeling》
  • Leetcode—2660.保龄球游戏的获胜者【简单】
  • ubuntu服务器上安装KVM虚拟化
  • SpreadJS 集成使用案例
  • 单挑力扣(LeetCode)SQL题:534. 游戏玩法分析 III(难度:中等)
  • 【OpenCV】告别人工目检:深度学习技术引领工业品缺陷检测新时代
  • VR全景图片制作时有哪些技巧,VR全景图片能带来哪些好处
  • 【VUE】Flask+vue-element-admin前后端分离项目发布到linux服务器操作指南
  • django的gunicorn的异步任务执行
  • KEPServerEX 6 之【外篇-2】PTC-ThingWorx服务端软件安装 PostgreSQL本地安装
  • websocket 介绍
  • 【IoT网络层】STM32 + ESP8266 +MQTT + 阿里云物联网平台 |开源,附资料|
  • 数据分析工具 Top 8
  • AI 换脸的新时代:没有显卡也可以使用的AI换脸工具
  • 3.Python中的循环结构
  • 机器学习之BP神经网络精讲(Backpropagation Neural Network(附案例代码))
  • 安全生产人员定位系统助企业实现智能化管理,提高生产安全性和效率
  • 动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本
  • Hadoop集群找不到native-hadoop
  • 解决阿里云远程连接yum无法安装问题(Ubuntu 22.04)
  • springboot 查询
  • 【分布式链路追踪技术】sleuth+zipkin
  • Windows 源码编译 MariaDB
  • 【动画视频生成】
  • 《Spring Cloud学习笔记:微服务保护Sentinel》
  • 解密负载均衡:如何平衡系统负载(下)
  • go 源码解读 - sync.Mutex
  • 机器学习系列--R语言随机森林进行生存分析(1)
  • <JavaEE> TCP 的通信机制(四) -- 流量控制 和 拥塞控制