JAVA-CopyOnWrite并发集合

文章目录

    • JAVA并发集合
    • 1_实现原理
    • 2_什么是CopyOnWrite?
    • 3_CopyOnWriteArrayList的原理
    • 4_CopyOnWriteArraySet
    • 5_使用场景
    • 6_总结

JAVA并发集合

从Java5开始,Java在java.util.concurrent包下提供了大量支持高效并发访问的集合类,它们既能包装良好的访问性能,有能包装线程安全。这些集合类可以分为两部分,它们的特征如下:

  • 以Concurrent开头的集合类:
    以Concurrent开头的集合类代表了支持并发访问的集合,它们可以支持多个线程并发写入访问,
    这些写入线程的所有操作都是线程安全的,但读取操作不必锁定。以Concurrent开头的集合类
    用了更复杂的算法来保证永远不会锁住整个集合
    ,因此在并发写入时有较好的性能。
  • 以CopyOnWrite开头的集合类:
    以CopyOnWrite开头的集合类采用复制底层数组的方式来实现写操作。当线程对此类集合执行读
    取操作时,线程将会直接读取集合本身,无须加锁与阻塞。当线程对此类集合执行写入操作时,集
    合会在底层复制一份新的数组,接下来对新的数组执行写入操作。由于对集合的写入操作都是对数
    组的副本执行操作
    ,因此它是线程安全的。
  • 扩展阅读
    java.util.concurrent包下线程安全的集合类的体系结构:
    在这里插入图片描述

本文将主要讲解以CopyOnWrite开头的集合类:

1_实现原理

在Java中,CopyOnWrite系列的集合(如CopyOnWriteArrayListCopyOnWriteArraySet)是线程安全的集合类,适用于读操作频繁且写操作相对较少的场景。它们通过一种名为 “写时复制”(Copy-On-Write,简称COW)的策略来实现线程安全。

2_什么是CopyOnWrite?

概括为"写时复制",通俗的讲是写数据的时候弄出一个新的数组,然后讲旧的数据拷贝过去,更新后再将引用指向新数组。这样在添加删除元素时就不会影响旧数组的读取了,确保高并发时读的效率,但是存在延时。

下面以CopyOnWriteArrayListCopyOnWriteArraySet为例对CopyOnWrite系列的集合进一步讲解。

3_CopyOnWriteArrayList的原理

CopyOnWriteArrayList是一个线程安全的可变数组实现,内部通过复制底层数组来处理并发写操作。其主要特性是:

  • 读操作不需要锁:因为读操作不会修改数组,因此可以并发进行。
  • 写操作通过复制实现:每次写操作(如添加、删除、更新)都会创建底层数组的一个新副本,修改副本后再将其设置为新的底层数组。

内部实现机制:

以下是CopyOnWriteArrayList的核心实现机制:

  • 底层数据结构
    CopyOnWriteArrayList内部使用一个volatile修饰的数组来存储元素,确保多线程环境下对数组的可见性。

    private transient volatile Object[] array;
    
  • 读操作

    读操作直接访问底层数组,无需加锁。

    public E get(int index) {return get(array, index);
    }final Object[] getArray() {return array;
    }private E get(Object[] a, int index) {return (E) a[index];
    }
    
  • 写操作

    写操作在进行修改时,会首先复制底层数组,然后在新数组上进行修改,最后将新数组设置为底层数组。

    public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();       // 获取当前数组int len = elements.length;            // 获取当前数组的长度Object[] newElements = Arrays.copyOf(elements, len + 1); // 复制数组,并增加一个位置newElements[len] = e;                 // 将新元素添加到新数组的最后一个位置setArray(newElements);                // 用新数组替换旧数组return true;} finally {lock.unlock();                        // 释放锁}
    }final void setArray(Object[] a) {array = a;
    }
    

在这个示例中,add方法首先获取锁以确保写操作的线程安全。然后,它复制现有的数组,增加一个新元素,并将新数组设置为底层数组。

添加操作会复制新的数组并将原元素长度加一,那么移除一个元素呢?

  • 移除操作:
    public boolean remove(Object o) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;// 寻找要移除的元素的位置int i = 0;for (; i < len; i++) {if (o.equals(elements[i])) {break;}}// 如果没有找到元素,直接返回falseif (i == len) {return false;}// 创建新数组,长度比当前数组少一个Object[] newElements = new Object[len - 1];// 复制前面的元素System.arraycopy(elements, 0, newElements, 0, i);// 复制后面的元素System.arraycopy(elements, i + 1, newElements, i, len - i - 1);// 设置新数组setArray(newElements);return true;} finally {lock.unlock();}
    }

CopyOnWriteArrayList中,移除元素的操作也是通过复制数组并在新数组上进行操作来实现的。虽然每次移除操作都会创建一个新数组,存在一定的性能开销,但这种设计能够确保线程安全,适合读多写少的场景。

既然remove、add已经了解了,那么 set 也就不难猜测了,public E set(int index, E element)操作时也是拷贝原数组然后进行操作,只不过长度相对原数组既没有增加也没有减少。

4_CopyOnWriteArraySet

CopyOnWriteArraySet是基于CopyOnWriteArrayList实现的线程安全的集合。它利用CopyOnWriteArrayList来存储元素,并确保集合中的元素不重复。

5_使用场景

CopyOnWrite集合适用于以下场景:

  1. 读多写少:由于每次写操作都会复制整个数组,因此写操作的开销较大。适用于读操作频繁、写操作较少的场景。
  2. 遍历操作:在遍历过程中,不会受到并发修改的影响,因为任何写操作都会创建一个新的数组副本,不会修改正在遍历的数组。

优缺点

优点

  • 线程安全:通过写时复制机制实现线程安全,读操作无锁,性能高。
  • 适用于读多写少的场景:在读操作远多于写操作的情况下,性能表现优秀。
  • 不需要手动同步:用户无需手动添加同步代码,简化了并发编程。

缺点

  • 内存开销大:每次写操作都会创建数组副本,占用额外的内存。
  • 写操作性能差:写操作需要复制数组,性能较低。

示例代码

以下是CopyOnWriteArrayList的简单示例代码:

import java.util.concurrent.CopyOnWriteArrayList;public class CopyOnWriteExample {public static void main(String[] args) {CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();// 添加元素list.add(1);list.add(2);list.add(3);// 读取元素System.out.println("Element at index 0: " + list.get(0));// 遍历元素for (Integer element : list) {System.out.println("Element: " + element);}// 删除元素list.remove(Integer.valueOf(2));System.out.println("After removal: " + list);}
}

6_总结

CopyOnWrite系列集合通过写时复制机制实现线程安全,适用于读操作频繁且写操作较少的场景。虽然写操作的开销较大,但在读操作占多数的应用中,CopyOnWrite集合可以提供高效且线程安全的性能。

CopyOnWriteArrayList中,移除元素的操作与添加元素类似,通过复制数组并在新数组上进行操作来实现线程安全。移除元素时,需要创建一个新的数组,长度比当前数组少一个,然后复制所有不需要移除的元素到新数组中。

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

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

相关文章

无人机的发展

朋友们&#xff0c;你们知道吗&#xff1f;无人机的发展之路可谓是科技界的一股清流&#xff0c;风头正劲啊&#xff01;从最初简单的遥控飞机到现在各种智能功能的加持&#xff0c;无人机真是越来越神奇了&#xff01; 首先&#xff0c;无人机在航拍领域大放异彩&#xff01;无…

ETL可视化工具 DataX -- 简介( 一)

引言 DataX 系列文章&#xff1a; ETL可视化工具 DataX – 安装部署 ( 二) 1.1 DataX 1.1.1 Data X概览 DataX 是阿里云DataWorks数据集成的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServ…

ChatGPT 提示词技巧一本速通

一、基本术语 概念 定义 案例 提示词 prompt 向AI模型提出的问题或者指示&#xff0c;告诉它我们希望得到什么样的回答或结果&#xff0c;是与模型互动的主要形式。 任务&#xff1a;生成一封电子邮件邀请。 提示词&#xff1a;请帮我写一封邀请同事参加下周五团队建设活…

Vue引入element-plus-04

我们这次开发是使用vue的脚手架来进行开发,前面我们已经使用过最原生的方式去编写我们的vue的语法,从今天开始就使用vue的脚手架,但是前提是你需要用于node的环境 在我们开始之前&#xff0c;我们至少需要有node npm是什么&#xff1f; npm是一个强大的包管理工具&#xff0c;它…

Stable Diffusion【应用篇】【艺术写真】:粘土风之后陶瓷风登场,来看看如何整合AI艺术写真吧

在国外的APP Remini引爆了粘土滤镜后&#xff0c;接着Remini又推出了瓷娃娃滤镜。相当粘土滤镜&#xff0c;个人更喜欢瓷娃娃滤镜&#xff0c;因为陶瓷工艺更符合东方艺术审美。 下面我们就来看看陶瓷特效在AI写真方面的应用。话不多说&#xff0c;我们直接开整。 关于粘土整…

基于BERT微调+模板填充快速实现文本转DSL查询语句

前言 Text2SQL是指将自然语言转化为类SQL查询语句&#xff0c;使得用户的查询文本可以直接实现和数据库交互&#xff0c;本文介绍一种以BERT为基础模型&#xff0c;通过模板填充来实现的Text2SQL算法和产品化。 内容摘要 Text2SQL任务说明模板填充的思路条件列选择子模型搭建…

TCGAbiolinks包学习

TCGAbiolinks 写在前面学习目的GDCquery GDCdownload GDC prepare中间遇到的报错下载蛋白质数据 写在前面 由于别人提醒我TCGA的数据可以利用TCGAbiolinks下载并处理&#xff0c;所以我决定阅读该包手册&#xff0c;主要是该包应该是有更新的&#xff0c;我看手册进行更新了&…

Kotlin编程实践-【Java如何调用Kotlin中带默认值参数的函数】

问题 如果你有一个带有默认参数值的 Kotlin 函数&#xff0c;如何从 Java 调用它而无须为每个参数显式指定值&#xff1f; 方案 为函数添加注解JvmOverloads。 也就是为Java添加重载方法&#xff0c;这样Java调用Kotlin的方法时就不用传递全部的参数了。 示例 在 Kotlin …

干部管理软件有哪些

随着信息技术的飞速发展&#xff0c;干部管理软件在各级党政机关、国企事业单位中扮演着越来越重要的角色。这些软件通过整合干部管理的各项业务流程&#xff0c;实现了干部信息的系统化、规范化和高效化管理。以下是几款主流的干部管理软件及其特点&#xff1a; 一、干部信息…

基于python深度学习的CNN图像识别鲜花-含数据集+pyqt界面

代码下载&#xff1a; https://download.csdn.net/download/qq_34904125/89383615 本代码是基于python pytorch环境安装的。 下载本代码后&#xff0c;有个requirement.txt文本&#xff0c;里面介绍了如何安装环境&#xff0c;环境需要自行配置。 或可直接参考下面博文进行…

AI 一键换脸,背景替换,ioDraw让图片更有趣

还在为繁琐的图片处理而烦恼吗&#xff1f;快来试试ioDraw的AI图片工具&#xff01; 它集图像识别、图像生成、智能换脸、背景替换、图像融合、肖像风格化、空间风格化、智能扩图、智能抠图、画质提升、美颜、拉伸修复、透视校正等功能于一身&#xff0c;为你提供前所未有的图…

(Javascript)AI数字人mp4转canvas播放并去除背景绿幕

1、需求介绍 H5页面嵌入AI数字人播报&#xff0c;但生成的数字人是mp4格式且有绿幕背景&#xff0c;需要转成canvas并去除背景&#xff1b; 2、效果&#xff1a; 去除前&#xff1a; 去除后&#xff1a; 3、代码 <!DOCTYPE html> <html lang"en"><…

【第9章】Vue之Element Plus快速入门

文章目录 前言一、安装1. 兼容性2. 安装 二、按需导入1.自动导入2.Vite 三、全局配置四、官方案例五、效果总结 前言 基于 Vue 3&#xff0c;面向设计师和开发者的组件库。 一、安装 1. 兼容性 Element Plus 目前还处于快速开发迭代中。 由于 Vue 3 不再支持 IE11&#xff0c…

Opus从入门到精通(五)OggOpus封装器全解析

Opus从入门到精通(五)OggOpus封装器全解析 为什么要封装 前面Opus从入门到精通(四)Opus解码程序实现提到如果不封装会有两个问题: 无法从文件本身获取音频的元数据(采样率,声道数,码率等)缺少帧分隔标识,无法从连续的文件流中分隔帧(尤其是vbr情况) 针对上面的问题我们可以…

北京活动会议通常会邀约哪些媒体参会报道?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 北京作为我国的首都和文化中心&#xff0c;各类活动会议资源丰富&#xff0c;吸引了众多媒体的关注。以下是一些通常会被邀约参会报道的重要媒体类型&#xff1a; 国家级新闻机构&#x…

flink standalone部署模式

standalone模式可以在单台机器以不同进程方式启动&#xff0c;也可以以多机器分布式方式启动。 任务的提交模式有三种&#xff1a;application mode、session model、per-job mode&#xff08;1.4x版本后过时&#xff09;。 注意区分任务的提交模式与集群的部署模式区别。 以…

注册中心理论学习

注册中心介绍 注册中心&#xff08;也称为服务注册中心或服务发现服务&#xff09;是微服务架构中的一个关键组件&#xff0c;它负责服务的注册与发现。在微服务体系中&#xff0c;服务实例的数量和位置是动态变化的&#xff0c;注册中心提供了一个集中的地方来存储这些信息&a…

linux中DNS域名解析服务(后续补充)

分离解析简介&#xff1a; 分离解析的域名服务器实际也是主域名服务器&#xff0c;这里主要是指根据不同的客户端提供不同的域名解析记录。比如来自内网和外网的不同网段地址的客户机请求解析同一域名时&#xff0c;为其提供不同的解析结果。 实验要求&#xff1a;防火墙要么关…

AMSR-MODIS 边界层水汽 L3 每日 1 度 x 1 度 V1、V2 版本数据集

AMSR-MODIS Boundary Layer Water Vapor L3 Daily 1 degree x 1 degree V1 (AMDBLWV) at GES DISC AMSR-MODIS Boundary Layer Water Vapor L3 Daily 1 degree x 1 degree V2 (AMDBLWV) at GES DISC 简介 该数据集可估算均匀云层下的海洋边界层水汽。AMSR-E 和 AMSR-2 的微波…

在C#中对 JSON进行序列化和反序列化处理

概述&#xff1a;在现代软件开发领域&#xff0c;不同系统和平台之间的数据交换是不可或缺的方面。JSON&#xff08;JavaScript 对象表示法&#xff09;因其轻量级、人类可读和易于解析的特性而成为一种无处不在的数据格式。使用 C# &#x1f680;编程的 JSON 序列化和反序列化…