Java 集合 线程安全
Java中常用的集合框架中的实现类HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap、TreeMap都是线程不安全的,如果多个线程同时访问它们,而且有超过一个的线程试图修改它们,则存在线程安全的问题。
Hashtable:
Hashtable是线程安全的,任意时刻只能有一个线程对Hashtable进行操作,并发性不如ConcurrentHashMap,因为后者引入了分段锁
Hashtable的线程安全使用的是一个单独的全部Map范围的锁,这个锁在所有的插入、删除、查询操作中都会持有,甚至在使用Iterator遍历整个Map时也会持有这个单独的锁。当锁被一个线程持有时,就能够防止其他线程访问该Map,即便其他线程都处于闲置状态。这种单个锁机制极大的限制了并发的性能
参考博客:http://blog.csdn.net/zcc_0015/article/details/46932667
Collections.sychroinzedXxx():
Collections提供了多个synchronizedXxx()方法可以将指定集合包装成线程同步的集合,从而解决多线程并发访问集合时的线程安全问题
Collections.synchronizedMap(map);
Collections.synchronizedList(list);
Collections.synchronizedSet(set);
以synchronizedMap()为例,它的方法实现如下,接受一个map对象,返回一个SynchronizedMap<>对象
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
return new SynchronizedMap<>(m);
}
我们再来看SynchronizedMap<>类,它实现了Map<K,V>接口,并且是可序列化的,它有两个构造方法,而且使用了synchronized来保证对Map的操作是线程安全的
private static class SynchronizedMap<K,V>
implements Map<K,V>, Serializable {
private static final long serialVersionUID = 1978198479659022715L; private final Map<K,V> m; // Backing Map
final Object mutex; // Object on which to synchronize SynchronizedMap(Map<K,V> m) {
this.m = Objects.requireNonNull(m);
mutex = this;
} SynchronizedMap(Map<K,V> m, Object mutex) {
this.m = m;
this.mutex = mutex;
} public int size() {
synchronized (mutex) {return m.size();}
}
public boolean isEmpty() {
synchronized (mutex) {return m.isEmpty();}
}
public boolean containsKey(Object key) {
synchronized (mutex) {return m.containsKey(key);}
}
public boolean containsValue(Object value) {
synchronized (mutex) {return m.containsValue(value);}
}
public V get(Object key) {
synchronized (mutex) {return m.get(key);}
} public V put(K key, V value) {
synchronized (mutex) {return m.put(key, value);}
}
public V remove(Object key) {
synchronized (mutex) {return m.remove(key);}
}
public void putAll(Map<? extends K, ? extends V> map) {
synchronized (mutex) {m.putAll(map);}
}
public void clear() {
synchronized (mutex) {m.clear();}
}
}
但是我们进一步考虑,这里的get、set、remove等方法是同步的,也就是说我们对map的操作是线程安全的,但是它们之间呢?比如说:用户A对map进行了get操作,准备remove map中的元素;而此时,用户B也对map进行get操作,然后remove了这一项,此时,用户A开始做remove的时候,发现这个元素已经不存在了,这段操作显然不是线程安全的,我们显然需要将整个map锁住,这样的话,效率就会大大降低
ConcurrentHashMap:
Java5新增了ConcurrentMap接口和它的一个实现类ConcurrentHashMap,ConcurrentHashMap提供了和HashTable、SynchronizedMap种不同的锁机制。Hashtable中采用的锁机制是一次锁住整个hash表,从而同一时刻只能由一个线程对其进行操作;而ConcurrentHashMap中则是一次锁住一个桶。ConcurrentHashMap默认将hash表分为16个桶,诸如get,put,remove等常用操作只锁当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的
ConcurrentHashMap抛弃了HashTable的单锁机制,使用了锁分离技术,使得多个修改操作能够并发进行。ConcurrentHashMap内部使用段(Segment),默认是16个段,来表示这些不同的部分,每个段其实就是一个小的hash table,即通过多个锁来控制对不同段的hash表的修改,每个锁只负责一部分key的hash值范围。只要多个修改操作发生在不同的段上,它们就可以并发进行
CopyOnWrite:
同步的实例方法在执行之前都会隐式的需要一个锁。java中 也可以显示的调用锁,CopyOnWrite容器就是用ReentrantLock锁实现的,ReentrantLock是为创建相互排斥的锁的Lock的具体实现
CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器
参考链接:http://blog.csdn.net/mark_wk/article/details/22588263
https://zhidao.baidu.com/question/1692121547117149828.html
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();
}
}
Java 集合 线程安全的更多相关文章
- java集合 线程安全
1.快速失败(fail-fast)和安全失败(fail-safe)? 一:快速失败(fail—fast) 在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加.删除.修改),则 ...
- Java集合--线程安全(CopyOnWrite机制)
5 Java并发集合 5.1 引言 在前几章中,我们介绍了Java集合的内容,具体包括ArrayList.HashSet.HashMap.ArrayQueue等实现类. 不知道各位有没有发现,上述集合 ...
- java集合线程安全测试
package com.cxy; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import ...
- java利用线程池处理集合
java利用线程池处理集合 2018年07月23日 17:21:19 衍夏成歌 阅读数:866 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/s ...
- 08 Java 集合的线程安全问题
1 Java中的集合 Java中的集合分为同步的集合(线程安全)和线程不安全的集合 例如 : ArrayList和Vector的区别: 一.同步性:Vector是线程安全的,也就是说是同步的,而Arr ...
- java面试| 线程面试题集合
集合的面试题就不罗列了,基本上在深入理解集合系列已覆盖 「 深入浅出 」java集合Collection和Map 「 深入浅出 」集合List 「 深入浅出 」集合Set 这里搜罗网上常用线程面试题, ...
- java 集合及其线程安全 及其 set linkedList map table 区别
早在jdk的1.1版本中,所有的集合都是线程安全的.但是在1.2以及之后的版本中就出现了一些线程不安全的集合,为什么版本升级会出现一些线程不安全的集合呢?因为线程不安全的集合普遍比线程安全的集合效率高 ...
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- java集合你了解多少?
用了java集合这么久,还没有系统的研究过java的集合结构,今天亲自画了下类图,总算有所收获. 一.所有集合都实现了Iterable接口. Iterable接口中包含一个抽象方法:Iterator& ...
随机推荐
- JAVA中static什么作用?
是静态修饰符,什么叫静态修饰符呢?大家都知道,在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的,而所谓静态就是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个空间,也就是只 ...
- 关于CGI和FastCGI的理解
在搭建 LAMP/LNMP 服务器时,会经常遇到 PHP-FPM.FastCGI和CGI 这几个概念.如果对它们一知半解,很难搭建出高性能的服务器. 0.CGI的引入 在网站的整体架构中,Web Se ...
- LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】
LINK 思路 首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小 ...
- SUST OJ 1642: 绝地求生—死亡顺序
1642: 绝地求生-死亡顺序 时间限制: 1 Sec 内存限制: 128 MB提交: 81 解决: 53[提交][状态][讨论版] 题目描述 最近陕西科技大学六公寓的小东同学深深的入迷了一款游戏 ...
- The Suspects 并查集
Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized ...
- day34 python学习 守护进程,线程,互斥锁,信号量,生产者消费者模型,
六 守护线程 无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁 需要强调的是:运行完毕并非终止运行 #1.对主进程来说,运行完毕指的是主进程代码运行完毕 #2.对主线程来说,运行完 ...
- hangfire docker-compose 运行
hangfire 是一款基于.net 的任务调度系统 docker-compose 文件 version: '3' services: hangfire: image: direktchark/han ...
- hasura graphql 集成pipelinedb测试
实际上因为pipelinedb 是原生支持pg的,所以应该不存在太大的问题,以下为测试 使用doker-compose 运行 配置 docker-compose 文件 version: '3.6' s ...
- kettle的输入输出组件和脚本组件
一. 输入组件 1.1表输入 从指定的数据库中,通过sql语句来查询数据加载到内存. 允许简易转换:勾选后可以避免不必要的字段的数据类型转换,从而提高性能. 替换sql语句里的变量:勾选后可以通过${ ...
- Maven的dependency type属性
官方地址: http://maven.apache.org/ref/3.5.2/maven-model/maven.html (搜索:Some examples are jar, war, ejb-c ...