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

验证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 中包含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[] …

Shiro介绍及主要流程

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

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 展现…

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

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

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;下面这个现象 那为什么会…

String、StringBuilder、StringBuffer的区别

它们之间的区别&#xff1a; 在我们学习String类的时候&#xff0c;也会学习到StringBuilder和StringBuffer&#xff0c;但是他们之间有什么区别呢&#xff1f; 当然他们在具体的代码实现上、内存分配上以及效率上都有着不同&#xff08;我这里以JDK8为例&#xff09;&#xff…

2016年 java_2016年java考试试题及答案

2016年java考试试题及答案简答应用题1.下面程序运行后&#xff0c;可以使用上下左右键移动组件。 补充下画线部分的代码。import java.awt.*;import java.awt.event.*;public class E6 extends Frame implements keyListener{TextField b1;int x,y;E6(){setLayout (new FlowLay…

【Java深入理解】String str = “a“ + “b“ + “c“到底创建了几个对象?

String str “a” “b” “c"到底创建了几个对象&#xff1f;这是我们在讨论中最经常遇到的一个问题同时也是面试题。我们都知道在Java中从”.java"文件编译成".class"文件的过程&#xff0c;会有一个优化器去优化我们的代码。这个问题需要分成三种情况…

Linux中如何查看某个端口是否被占用

Linux中如何查看某个端口是否被占用 1.netstat -anp |grep 端口号 如下&#xff0c;我以3306为例&#xff0c;netstat -anp |grep 3306&#xff08;此处备注下&#xff0c;我是以普通用户操作&#xff0c;故加上了sudo&#xff0c;如果是以root用户操作&#xff0c;不用加sudo…

java 压缩jar 仓库,java服务安装(一):使用java service wrapper及maven打zip包

tags&#xff1a; java jsw maven zip1、概述使用java开发程序&#xff0c;在windows平台下&#xff0c;一般有web应用&#xff0c;后台服务应用&#xff0c;桌面应用&#xff1a;web应用多数打成war包在web容器(如tomcat,jetty等)中运行桌面应用一般打成jar包或exe文件运行后台…

如何处理代码冲突

如何处理代码冲突 冲突合并一般是因为自己的本地做的提交和服务器上的提交有差异&#xff0c;并且这些差异中的文件改动&#xff0c;Git不能自动合并&#xff0c;那么就需要用户手动进行合并 如我这边执行git pull origin master 如果Git能够自动合并&#xff0c;那么过程看…

如何理解NIO

文章目录1.什么是NIO&#xff1f;2.为什么用NIO&#xff0c;传统IO有什么缺陷&#xff1f;3.NIO和IO的区别4.怎么理解NIO是面向块的、非阻塞的5.NIO是怎么实现的&#xff1f;1.什么是NIO&#xff1f; java.nio全称java non-blocking IO&#xff08;实际上是 new io&#xff09…

sublime php快捷键,分享Sublime Text 3快捷键精华版!

下面由sublime教程栏目给大家介绍Sublime Text 3 快捷键精华版&#xff0c;希望对需要的朋友有所帮助&#xff01;CtrlShiftP&#xff1a;打开命令面板CtrlP&#xff1a;搜索项目中的文件CtrlG&#xff1a;跳转到第几行CtrlW&#xff1a;关闭当前打开文件CtrlShiftW&#xff1a…

JDBC中使用preparedStatement防止SQL注入

一、SQL注入 SQL注入是一种比较常见的网路攻击方式&#xff0c;一些恶意人员在需要用户输入的地方&#xff0c;恶意输入SQL语句的片段&#xff0c;通过SQL语句&#xff0c;实现无账号登录&#xff0c;甚至篡改数据库。 二、SQL注入实例 登录场景&#xff1a; 在一个登录界面…

Java预科篇1-学前

Java预科篇1-学前 1、markdown语法 Markdown是一种纯文本格式的标记语言。通过简单的标记语法&#xff0c;它可以使普通文本内容具有一定的格式。 优点&#xff1a; 因为是纯文本&#xff0c;所以只要支持Markdown的地方都能获得一样的编辑效果&#xff0c;可以让作者摆脱排…

Java预科篇2-环境搭建

Java预科篇2-环境搭建 1、Java历史 1995年 Java问世1996年 Java 1.01999年 Java 1.2发布&#xff08;JAVA SE\JAVA EE\JAVA ME&#xff09;… … …2004年 Tiger 发布(JAVA5.0)&#xff0c;Java 登录火星2011年 7月由Oracle正式发布Java7.02014年 3月19日&#xff0c;Oracle公…

php中如何配置环境变量,如何配置phpstorm环境变量如何配置phpstorm环境变量

大话西游6664版。根据你的系统平台下载相应的版本后&#xff0c;如果是压缩文件&#xff0c;先解压后双击运行&#xff0c;不是压缩文件&#xff0c;直接双击运行就可以了&#xff0c;运行后出现下面的界面&#xff0c;在下面界面上单击“Next”。跟所有的软件安装包一样&#…

Java基础篇1——变量与数据类型

Java基础篇1——变量与数据类型 1、标识符命名规则 标识符以由大小写字母、数字、下划线(_)和美元符号($)组成&#xff0c;但是不能以数字开头。大小写敏感不能与Java语言的关键字重名不能和Java类库的类名重名不能有空格、、#、、-、/ 等符号长度无限制应该使用有意义的名称…