java 集合读写同步_JAVA多线程学习十六 - 同步集合类的应用

1.引言

在多线程的环境中,如果想要使用容器类,就需要注意所使用的容器类是否是线程安全的。在最早开始,人们一般都在使用同步容器(Vector,HashTable),其基本的原理,就是针对容器的每一个操作,都添加synchronized来进行同步,此种方式尽管简单,但是其性能是非常地下的,所以现在已经不怎么使用了。人们普遍会使用并发的容器,在JDK1.5之后,针对基于散列的Map,提供了新的ConcurrentHashMap,针对迭代需求的list,提供了CopyOnWriteList.

2.ConcurrentHashMap

ConcurrentHashMap使用了一种分段锁的策略,使得map可以被多个读写线程并行的访问。基本可以认为是将map的key值范围分为多个段,这样多个线程访问的时候,他们需要访问的key值在不同的段,所以可以互相不干扰,

使用不同的锁对象来进行并发操作。

ConcurrentHashMap在使用迭代器遍历的时候,不会报ConcurrentModificationException,提供“弱一致性”。在遍历迭代的时候,也会反应出在迭代器创建之后的数据修改。

应用场景

针对一般的有并发需求的map,都应该使用ConcurrentHashMap. 它的性能优于Hashtable和synchronizedMap。

缺点

不是强一致性

由于是采用的分段锁策略,所以一些数据不能保证强一致性。比如针对容器的size方法,由于线程A只是获得了自己的分段锁,它不能保证其他线程对容器的修改,所以此时线程A可能使用size,会得到不稳定数据。这种情况下,是对同步性能的一些折衷。如果业务需求必须满足强一致性,才会需要对整个Map进行锁操作。并发容器的弱一致性的概念背景,是在高并发情况下,容器的size和isEmpty之类的方法,用处不大,所以可以忍受数据不一致性。

3.CopyOnWrite容器

在JDK1.5之后,java.util.concurrent引入了两个CopyOnWrite容器,分别是CopyOnWriteArrayList, CopyOnWriteArraySet.

顾名思义,CopyOnWrite就是在write操作之前,对集合进行Copy,针对容器的任意改操作(add,set,remove之类),都是在容器的副本上进行的。并且在修改完之后,将原容器的引用指向修改后的副本。

如果线程A得到容器list1的iterator之后,线程B对容器list1加入了新的元素,由于线程A获得list1的iterator时候在线程B对list1进行修改前,所以线程A是看不到线程B对list1进行的任何修改。

具体到源码,看一下add操作

48304ba5e6f9fe08f3fa1abda7d326ab.png

/**

* Appends the specified element to the end of this list.

*

* @param e element to be appended to this list

* @return {@code true} (as specified by {@link Collection#add})

*/

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();

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

可以发现,写操作是会有个锁lock.lock(),这保证了多线程写操作之间的同步。之后使用Arrays.copyOf来进行数组拷贝,在修改完成后,setArray(newElements)将原来的数组引用指向新的数组。

应用场景

经常用在读多写少的场景,比如EventListener的添加,网站的category列表等偶尔修改,但是需要大量读取的情景。

缺点

1.数据一致性的问题。

因为读操作没有用到并发控制,所以可能某个线程读到的数据不是实时数据。

2.内存占用问题。

因为写操作会进行数据拷贝,并且旧有的数据引用也可能被其他线程占有一段时间,这样针对数据比较大的情况,可能会占用相当大的内存。并且由于每次写操作都会占用额外的内存,最后进行的GC时间也可能相应的增加。

4.HashSet

HashSet内部是用的HashMap,只用了HashMap的key。

同步集合

传统集合类在并发访问时的问题说明:死锁死循环

传统方式下用Collections工具类提供的synchronizedCollection方法来获得同步集合,分析该方法的实现源码

Java5中提供了如下一些同步集合类:

通过看java.util.concurrent包下的介绍可以知道有哪些并发集合

ConcurrentHashMap

CopyOnWriteArrayList

CopyOnWriteArraySet

传统方式下的Conllection在迭代结合时,不允许对集合进行修改。

根据AbstractList的checkForComodification方法的源码,分析产生ConcurrentModificationException异常的原因。

48304ba5e6f9fe08f3fa1abda7d326ab.png

public class User implements Cloneable{

private String name;

private int age;

public User(String name, int age) {

this.name = name;

this.age = age;

}

public boolean equals(Object obj) {

if(this == obj) {

return true;

}

if(!(obj instanceof User)) {

return false;

}

User user = (User)obj;

//if(this.name==user.name && this.age==user.age)

if(this.name.equals(user.name)

&& this.age==user.age) {

return true;

}

else {

return false;

}

}

public int hashCode() {

return name.hashCode() + age;

}

public String toString() {

return "{name:'" + name + "',age:" + age + "}";

}

public Object clone() {

Object object = null;

try {

object = super.clone();

} catch (CloneNotSupportedException e) {}

return object;

}

public void setAge(int age) {

this.age = age;

}

public String getName() {

return name;

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

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

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

相关文章

Linux下的parted工具的使用 GPT分区安装系统

安装系统是安装前时候ctrlatlF2 fdisk -l parted select /dev/sdb mklabel msdos # 将GPT磁盘格式化为MBR磁盘 对大硬盘进行分区 xfs 和 ntfs Linux下的parted工具的使用也很简单,具体操作如下: rootme:/mnt# parted /dev/sda Using /dev/sda Welcome to…

ubuntu自定义菜单_如何自定义Ubuntu的每日消息

ubuntu自定义菜单Ubuntu displays an informative message, known as the message of the day, when a user logs in at the terminal. The MOTD is fully customizable — you can add your own text and other dynamic data. 当用户在终端上登录时,Ubuntu将显示信…

java避免使用orderby_java – @OrderBy在JPA中无法正常工作

OrderBy如何运作?它在以下代码中不起作用:Employee.javapackage com.semanticbits.pojo;import java.util.List;import javax.persistence.CascadeType;import javax.persistence.Embedded;import javax.persistence.Entity;import javax.persistence.Ge…

BigDecimal四舍五入与保留位

1.引言 借用《Effactive Java》这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果&#…

火狐web开发清楚缓存_如何使用Firefox的Web开发工具

火狐web开发清楚缓存Firefox’s Web Developer menu contains tools for inspecting pages, executing arbitrary JavaScript code, and viewing HTTP requests and other messages. Firefox 10 added an all-new Inspector tool and updated Scratchpad. Firefox的Web Develop…

Leetcode400Nth Digit第N个数字

在无限的整数序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...中找到第 n 个数字。 注意: n 是正数且在32为整形范围内 ( n < 231)。 示例 1: 输入: 3 输出: 3 示例 2: 输入: 11 输出: 0 说明: 第11个数字在序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... 里是0&#xff0c;它是…

Java基类共同属性设置_多选择基类的访问属性-Java初学笔记

多选择基类的访问属性你现在知道在定义类的访间属性时可用的选择项&#xff0c;你希望使用这些类定义子类。你知道在类继承上这些属性所具有的效果&#xff0c;但是你如何决定到底应该使用哪一个呢?这里没有死板和现成的规则&#xff0c;你选择的访问属性取决于在将来你想用类…

IT:如何在Windows Server 2008 R2上安装Hyper-V虚拟化

Windows Server 2008 R2 and later releases of the product ship with a virtualization platform called Hyper-V, which works quite well since it’s built into Windows. Today we’re going to show you how to install it. Windows Server 2008 R2和更高版本的产品附带…

FineReport单行与数据库交互的方法

1. 问题描述 我们在做一张报表填报的时候经常会遇到需要在一行进行添加动作&#xff0c;将该行数据直接与数据库交互&#xff0c;执行存储过程过程。我们可以通过每一行增加帆软“插入”按钮实现插入动作&#xff0c;并且在控件事件中增加和数据库的交互&#xff0c;但当事件…

java cas volatile_每日一个知识点:Volatile 和 CAS 的弊端之总线风暴

每日一个知识点系列的目的是针对某一个知识点进行概括性总结&#xff0c;可在一分钟内完成知识点的阅读理解&#xff0c;此处不涉及详细的原理性解读。一、什么是总线风暴总线风暴&#xff0c;听着真是一个帅气的词语&#xff0c;但如果发生在你的系统上那就不是很美丽了&#…

SqlServer之代码块相关

转载必需注明出处:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/sqlserver-codeblock/ 一、go语句 Go语句是SqlServer中用来表示当前代码块结束提交并确认结果的语句。 Go语句不能和其他Sql命令卸载同一行上&#xff01; 定义的局部变量作用域局限在定义它的代码…

010 使用list和tuple

list Python内置的一种数据类型是列表&#xff1a;list。list是一种有序的集合&#xff0c;可以随时添加和删除其中的元素。 比如&#xff0c;列出班里所有同学的名字&#xff0c;就可以用一个list表示&#xff1a; >>> classmates [Michael, Bob, Tracy] >>&g…

IT:如何使用Server 2008 R2上的远程桌面服务设置自己的终端服务器

In today’s IT learning article, we are going to take a look at installing Terminal Services, otherwise known as Remote Desktop Services, on a Server 2008 R2 machine. 在今天的IT学习文章中&#xff0c;我们将介绍在Server 2008 R2计算机上安装终端服务(也称为远程…

java 中的chartdata_获取Helm Charts中的文件夹列表

获得了位于templates文件夹之外的配置文件列表&#xff0c;我们将其输入到如下的helm图表中&#xff1a;├── configs│ ├── AllEnvironments│ │ ├── Infrastructure│ │ └── Services│ │ ├── ConfigFile1│ │ ├── ConfigFile2│ ├…

Win10 jdk的安装以及环境变量的配置,及需要注意的坑

此篇文章献给自己&#xff0c;希望下次长点记性 最近本人终于有时间开始学习appium&#xff0c;并且开始在电脑上配置环境&#xff0c;第一步就是在我那刚装的Win10 系统上安装jdk&#xff0c;过程并不顺利&#xff0c;由于之前都是用的win7&#xff0c;几乎都是一路的下一步&a…

java部分服务出现异常_Java web service 异常

1.org/apache/commons/discovery/tools/DiscoverSingletonException in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/discovery/tools/DiscoverSingleton缺少&#xff1a;commons-logging和commons-discovery2.ojava.lang.NoClassDefFoundErr…

Jenkins配置Findbugs做源代码安全扫描

2019独角兽企业重金招聘Python工程师标准>>> 此内容目标阅读用户&#xff1a;运维人员 配置步骤如下&#xff1a; Jenkins安装Findbugs插件 Jenkins系统管理 → 管理插件 → (可选插件)找到Findbugs及其依赖插件全部安装成功&#xff0c;Jenkins重启&#xff0c;即可…

如何从USB运行Windows 8 Developer Preview

Running Windows 8 from a USB should not be confused with installing Windows on a USB drive–in this case, instead of installing it on the drive, we’re just running it straight from the portable drive. Here’s how to do it. 从USB运行Windows 8不应与在USB驱动…

PAT-乙级-1042 字符统计

请编写程序&#xff0c;找出一段给定文字中出现最频繁的那个英文字母。 输入格式&#xff1a; 输入在一行中给出一个长度不超过 1000 的字符串。字符串由 ASCII 码表中任意可见字符及空格组成&#xff0c;至少包含 1 个英文字母&#xff0c;以回车结束&#xff08;回车不算在内…

acm教程 java版_[转]ACM之java速成

这里指的java速成&#xff0c;只限于java语法&#xff0c;包括输入输出&#xff0c;运算处理&#xff0c;字符串和高精度的处理&#xff0c;进制之间的转换等&#xff0c;能解决OJ上的一些高精度题目。1. 输入&#xff1a;格式为&#xff1a;Scanner cin new Scanner(newBuffe…