线程安全的集合类有哪些?

验证ArrayList线程不安全
ArrayList 应当是开发中用到的最多的集合类,是动态列表,List 接口的实现类。

多数情况下,我们实在单线程环境使用,或者是在方法内部,以局部变量的形式使用,一般不会出现线程安全问题。

但是当ArrayList置身于多线程环境时,很容易因为自身的fail-fast 机制抛出异常 ConcurrentModificationException 。

比如下面的代码

/*** 验证ArrayList的线程不安全,并提供几种线程安全的列表的解决方案** @author linjinjia linjinjia047@163.com* @date 2021/3/19 22:38*/
public class ListThreadSafeDemo {public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>();for (int i = 0; i < 10; i++) {final int j = i;new Thread(() -> {list.add(j);System.out.println(list);}, "" + i).start();}}
}

输出(输出结果不是唯一的,也有可能不抛出异常):
在这里插入图片描述

ConcurrentModificationException 可以作为一种检测bug的方式,但是不能在程序中依赖此异常。

线程安全的集合哪里找?

在众多的List 接口实现类中,总有一部分是为了线程安全而设计的。

使用 Collections.synchronizedList(List list) 方法
该方法像是一个包装操作,将传入的 list 进行包装,调用 list 的方法之前,进行同步处理。

返回列表对象的类,都是继承了一个 SynchronizedCollection 类,该类有一个成员变量 Object mutex,用来做同步处理时使用。
在这里插入图片描述
在调用List 的方法时,会先对 mutex 进行同步,然后再调用 c 对应的方法。追踪 synchronizedList 方法的源码,会很容易发现这一点。

Collections.synchronizedList(List list) 方法的注释中,指出了遍历返回列表时,建议手动进行同步,并给了个示例。

List list = Collections.synchronizedList(new ArrayList());...synchronized (list) {Iterator i = list.iterator(); // Must be in synchronized blockwhile (i.hasNext())foo(i.next());}

这是因为返回列表的 listIterator() 和 listIterator(int index) 方法都是直接返回 c 的迭代器,所以遍历需要自己进行同步。

使用Vector类
Vector 是 jdk1.0 的古老集合类,该类对大部分方法都加上了 synchronized 关键字,用来保证线程安全。

该类的 listIterator 和 iterator 返回的迭代器是支持 fail-fast 的。

还有一个 elements() 方法,返回一个 Enumeration 对象,只有 hasMoreElements() 和 nextElement()方法,不支持 fail-fast。

Vector 和 synchronizedList 的区别是,一个是Vector对方法加锁,无法控制锁的粒度;二是Vector进行加锁的对象是 this 本身,无法控制锁的对象。

使用 CopyOnWriteArrayList
CopyOnWrite 也叫 COW。

CopyOnWrite 容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器Object添加。

而是先将当前容器 Object[] 进行复制,复制一个新的容器 Object[] newElement 并往其中里添加元素,添加完元素之后,再将原容器的引用指向新的容器 setArray(new Element) 。

这样做的好处是可以对 CopyOnWrite 容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite 容器也是一种读写分离的思想,读和写不同的容器。
在这里插入图片描述
在这里插入图片描述
可以看到 add 方法中,是先复制原来的数组,然后增加新的元素,最后再赋值回原来的数组,这个过程是加锁的。

CopyOnWriteArrayList 适合读多写少的场景,写多的情况下,频繁地加锁和复制,也是一笔很大的开销。

拓展
以上三种方式适用于 List ,但是 Set 和 Map 也有类似的方式,去实现线程安全。

比如 Collections 中也有 synchronizedSetsynchronizedMap 方法,其原理也跟 synchronizedList 一样。

HashMap 和 HashTable 的关系犹如ArrayList 和 Vector 。

java.util.concurrent 下也有 CopyOnWriteSet, ConcurrentHashMap 这种线程安全的集合。

而且, CopyOnWriteSet 底层依赖的是 CopyOnWriteArrayList ,比如它的 add 方法就是调用了 CopyOnWriteArrayList 的 addIfAbsent() 方法。

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

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

相关文章

try-catch-finally的执行顺序

try-catch-finally的执行顺序 结论&#xff1a; 不管有没有出现异常&#xff0c;finally代码块都会执行&#xff1b;不管try和catch的代码块中有return时&#xff0c;finally仍会执行&#xff0c;且如果finally代码块也有return&#xff0c;则此代码肯定会返回finally执行的r…

java jdbc mysql url_java – 如何生成JDBC数据库URL?

我今天已经研究了大约3个小时,我觉得我很接近,但我有几个问题.我到目前为止找到的最好的信息来源是&#xff1a;https://stackoverflow.com/a/2840358,但它没有回答我的所有问题.一点背景&#xff1a;我正在使用Microsoft SQL Server 2014,并且我已经验证了IP地址127.0.0.1处于…

try catch finally 中包含return的几种情况,及返回结果

第一种情况&#xff1a;在try和catch中有return&#xff0c;finally中没有return&#xff0c;且finally中没有对try或catch中要 return数据进行操作的代码&#xff0c;这种情况也是最好理解的。 public class Test {public static int num1;public static void main(String[] …

java jp2launcher.exe_芯科cp2112有熟悉的吗?配置不能保存是什么原因?

文件夹PATH列表卷序列号为2474-602AC:.├─CP2112_SDK│ │ ReleaseNotes.txt│ ││ ├─Documentation│ │ ├─ApplicationNotes│ │ │ an495.pdf│ │ │ an496.pdf│ │ ││ │ ├─Datasheets│ │ │ CP2112.pdf│ │ ││ │ ├─Datash…

包装类的缓存问题

包装类的缓存问题 整型、char类型所对应的包装类&#xff0c;在自动装箱时&#xff0c;对于-128~127之间的值会进行缓存处理&#xff0c;其目的是提高效率。 缓存处理的原理为&#xff1a;如果数据在-128~127这个区间&#xff0c;那么在类加载时就已经为该区间的每个数值创建…

java中项目启动时加载_如何在项目启动时,加载或解析某配置文件

在web项目中有很多时候需要在项目启动时就执行一些方法&#xff0c;而且只需要执行一次&#xff0c;比如&#xff1a;加载解析自定义的配置文件、初始化数据库信息等等&#xff0c;在项目启动时就直接执行一些方法&#xff0c;可以减少很多繁琐的操作。在工作中遇到了项目初始数…

Shiro介绍及主要流程

Shiro介绍及主要流程 什么是Shiro Apache Shiro是一个强大且灵活的开源安全框架&#xff0c;易于使用且好理解&#xff0c;撇开了搭建安全框架时的复杂性。 Shiro可以帮助我们做以下几件事&#xff1a; 认证使用者的身份 提供用户的访问控制&#xff0c;比如&#xff1a; 决定…

java数据库程序实例_Java连接各种数据库的实例大全

1、Oracle8/8i/9i数据库(thin模式)Class.forName(“oracle.jdbc.driver.OracleDriver”)。newInstance()&#xff1b;String url“jdbc:oracle:thin:localhost:1521:orcl”;//orcl为数据库的SIDString user“test”;String password“test”;Connection conn DriverManager.get…

http的请求体body的几种数据格式

文章目录multipart/form-dataapplication/x-www-from-urlencodedrawbinarypostman中 Params和Body的区别multipart/form-data 以表单形式提交&#xff0c;主要是上传文件用它&#xff0c;在http中格式为 application/x-www-from-urlencoded 以键值对的数据格式提交 raw…

谷歌浏览器安装json格式化插件

谷歌浏览器安装json格式化插件 实际开发工作中经常用到json数据&#xff0c;那么就会有这样一个需求&#xff1a;在谷歌浏览器中访问URL地址返回的json数据能否按照json格式展现出来。 比如&#xff0c;在谷歌浏览器中访问&#xff1a;http://jsonview.com/example.json 展现…

java 俄罗斯方块窗口_[代码全屏查看]-java 俄罗斯方块

[1].[代码] [Java]代码package com;import java.awt.Color;import java.awt.Graphics;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.util.Random;import javax.swing.JFrame;import javax.swing.JPanel;public class Eluos extends JFrame{p…

vue3.0中使用Element-plus默认英文组件修改为中文

vue3.0中使用Element-plus默认英文组件修改为中文修改方法 说明&#xff1a;本方法Element-plus 1.0.2-beta.59 之前的版本可以&#xff0c;1.0.2-beta.59之后版本请看下一篇博客 1,引入element // ! element-plus vue3.0 import element from element-plus import element-…

在java中null的作用_在java中避免使用!= null有什么好处?

使用空集合或“空白”操作而不是null的主要优点是,大多数情况下,此类对象仍然可以在代码中工作而无需进一步修改.从本质上来说,空值更容易出错.请使用以下代码,例如&#xff1a;String[] names data.getNames();if (names ! null) {for (String name : names) {// Do stuff}}需…

新版Elemen Plus 国际化 1.0.2-beta.59(包含59)

根据官方文档可以找到解决办法。先来看一下官方文档内容 官方给出了两种方式。这里只研究第一种方式&#xff1a; <template><el-config-provider :locale"locale"><App /></el-config-provider> </template><script> import …

java开发亚马逊mws_GitHub - iotwlw/Amazon-MWS-SDK: 基于亚马逊MWS Java SDK 的封装

amazon-mws-java-sdk亚马逊MWS服务的Java-SDK封装安装在pom.xml中添加依赖top.guyi.amazonAmazon-MWS-SDK1.0.0.1依赖放在nexus私服中&#xff0c;并没有上传到中央仓库&#xff0c;所以请在pom.xml中加入仓库配置guyi-maple-nexushttp://nexus.guyi-maple.space/nexus/content…

oracle数据库中索引会失效的几种情况

创建Oracle 索引的目的是为了避免全表扫描数据&#xff0c;提高查询效率&#xff0c;但是如果sql语句写的不好致使索引失效&#xff0c;反而会影响数据查询效率。以下几种情况就会导致索引失效&#xff1a; 1. 没有 WHERE 子句 众所周知&#xff0c;添加索引的字段必需要在whe…

JAVA跑步计时器app_坚持跑步神器app

&#xfeff;坚持跑步神器app&#xff0c;让坚持不了自己跑步训练的人能够完成自己的训练目标&#xff0c;特色的惩罚系统时刻监督你跑步&#xff0c;不需要GPS就可以实现&#xff0c;非常方便&#xff0c;快来下载吧坚持跑步神器app介绍坚持跑步神器&#xff0c;设定每天跑步多…

java 中 BigDecimal 详解

首先&#xff0c;学习一个东西&#xff0c;我们都必须要带着问题去学&#xff0c;这边我分为 【为什么&#xff1f;】【是什么&#xff1f;】【怎么用&#xff1f;】 【为什么要用BigDecimal&#xff1f;】 首先&#xff0c;我们先看一下&#xff0c;下面这个现象 那为什么会…

三星s7不能运行java_在调试模式下启动时Android应用程序崩溃

当我在 debug 模式下运行时&#xff0c;应用程序崩溃了&#xff0c;但是当我正常运行它时它会起作用 . 我认为附加调试器时会出现问题 .日志&#xff1a;A/art: art/runtime/jdwp/jdwp_event.cc:661] Check failed: Thread::Current() ! GetDebugThread() (Thread::Current()0x…

关于vue-cli3中配置请求跨域的问题

关于vue-cli3中配置请求跨域的问题 根据Vue CLI3官方文档&#xff0c; 需要在vue.config.js文件中配置devServer.proxy选项来解决跨域问题。 1.关于vue.config.js文件 此文件在vue-cli3中不会自动生成&#xff0c;需要手动在项目根目录下创建。 2.配置devServer.proxy选项…