java并发:同步容器&并发容器
第一节 同步容器、并发容器
1.简述同步容器与并发容器
在Java并发编程中,经常听到同步容器、并发容器之说,那什么是同步容器与并发容器呢?同步容器可以简单地理解为通过synchronized来实现同步的容器,比如Vector、Hashtable以及SynchronizedList等容器,如果有多个线程调用同步容器的方法,它们将会串行执行。
可以通过查看Vector、Hashtable等同步容器的实现代码,可以看到这些容器实现线程安全的方式就是将它们的状态封装起来,并在需要同步的方法上加上关键字synchronized,但在某些情况下,同步容器不一定就是线程安全的,比如获取最后一个元素或者删除最后一个元素,我们需要实现额外的同步操作:
public static Object getLast(Vector list) {
int lastIndex = list.size() - 1;
return list.get(lastIndex);
}
public static void deleteLast(Vector list) {
int lastIndex = list.size() - 1;
list.remove(lastIndex);
}
虽然上面的方法看起来没有问题,Vector自身的方法也是同步的,但是在多线程环境中还是隐藏着问题。如果有两个线程A,B同时调用上面的两个方法,假设list的大小为10,这里计算得到的lastIndex为9,线程B首先执行了删除操作(多线程之间操作执行的不确定性导致),而后线程A调用了list.get方法,这时就会发生数组越界异常,导致问题的原因就是上面的复合操作不是原子操作,这里可以通过在方法内部使用list对象锁来实现原子操作。
同步容器会导致多个线程中对容器方法调用的串行执行,降低并发性,因为它们都是以容器自身对象为锁,所以在需要支持并发的环境中,可以考虑使用并发容器来替代。
并发容器是针对多个线程并发访问而设计的,在jdk5.0引入了concurrent包,其中提供了很多并发容器,如ConcurrentHashMap、CopyOnWriteArrayList等。
其实同步容器与并发容器都为多线程并发访问提供了合适的线程安全,不过并发容器的可扩展性更高。在Java5之前,程序员们只有同步容器,且在多线程并发访问的时候会导致争用,阻碍了系统的扩展性。Java5介绍了并发容器,并发容器使用了与同步容器完全不同的加锁策略来提供更高的并发性和伸缩性,例如,在ConcurrentHashMap中采用了一种粒度更细的加锁机制,可以称为分段锁,在这种锁机制下,允许任意数量的读线程并发地访问map,并且执行读操作的线程和写操作的线程也可以并发的访问map,同时允许一定数量的写操作线程并发地修改map,所以它可以在并发环境下实现更高的吞吐量,另外,并发容器提供了一些在使用同步容器时需要自己实现的复合操作,包括putIfAbsent等,但是由于并发容器不能通过加锁来独占访问,所以我们无法通过加锁来实现其他复合操作了。
2.参考资料:
(1)http://www.cnblogs.com/dolphin0520/p/3933404.html
第二节 ConcurrentHashMap
1.初识ConcurrentHashMap
针对并发容器中的ConcurrentHashMap,《java并发编程实战》一书有如下这样一段文字:

此处将揭开ConcurrentHashMap的神秘面纱,首先我们看一下ConcurrentHashMap的结构图,如下:

2.详述ConcurrentHashMap
(1)ConcurrentHashMap的并发度
ConcurrentHashMap把实际map划分成若干部分来实现它的可扩展性和线程安全。这种划分是使用并发度获得的,它是ConcurrentHashMap类构造函数的一个可选参数,默认值为16,这样在多线程情况下就能避免争用。
(2)ConcurrentHashMap的锁分离技术
HashTable容器在竞争激烈的并发环境下效率低下,原因是所有访问HashTable的线程都必须竞争同一把锁。若容器中有多把锁,每一把锁用于锁定容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁并访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

对比上图(该图摘自网络),同步容器HashTable实现锁的方式是锁整个hash表,而并发容器ConcurrentHashMap的实现方式是锁桶(简单理解就是将整个hash表想象成一大缸水,现在将这大缸里的水分到了几个水桶里,hashTable每次都锁定这个大缸,而ConcurrentHashMap则每次只锁定其中一个 桶)。
ConcurrentHashMap将hash表分为16个桶(默认值),诸如get,put,remove等常用操作只锁当前需要用到的桶。试想,原来只能一个线程进入,现在却能同时16个线程进入,并发性的提升是显而易见的。
(3)ConcurrentHashMap的remove操作
当对ConcurrentHashMap进行remove操作时,并不是进行简单的节点删除操作

对比上图,当对ConcurrentHashMap的一个segment(也就是一个桶中的节点)进行remove后,例如,删除节点C,C节点实际并没有被销毁,而是将C节点前面的反转并拷贝到新的链表中,C节点后面的不需要被克隆。这样的操作使并发的读线程不受并发的写线程的干扰,例如,现在有一个读线程读到了A节点,写线程把C删掉了,但是看上图,读线程仍然可以继续读下去;当然,如果在删除C之前读线程读到的是D,那么更不会有影响。
根据上面所提到的在ConcurrentHashMap中删除一个节点并不会立刻被读线程感受到的效果,就是传说中的弱一致性,所以ConcurrentHashMap的迭代器是弱一致性迭代器
3.参考资料:
本小节仅简单概述了ConcurrentHashMap的一些内容,其实现机制等可参考以下优质文章
(1)http://www.cnblogs.com/ITtangtang/p/3948786.html
(2)http://ifeve.com/concurrenthashmap/
(3)http://blog.csdn.net/xuefeng0707/article/details/40834595
java并发:同步容器&并发容器的更多相关文章
- java 多线程 同步 观察者 并发集合的一个例子
//第一版 package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type; import org.springfram ...
- Java多线程同步集合--并发库高级应用
一.阻塞队列1.在多线程领域,所谓阻塞,在某些情况下会挂起线程,一旦条件满足,被挂起的线程又会自动被唤醒2.ArrayBlockingQueue(效率高)和LinkedBlockingQueue是两个 ...
- Java并发——同步容器与并发容器
同步容器类 早期版本的JDK提供的同步容器类为Vector和Hashtable,JDK1.2 提供了Collections.synchronizedXxx等工程方法,将普通的容器继续包装.对每个共有方 ...
- Java并发--同步容器
为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch).今天我们就来讨论下同步容器. ...
- Java并发—同步容器和并发容器
简述同步容器与并发容器 在Java并发编程中,经常听到同步容器.并发容器之说,那什么是同步容器与并发容器呢?同步容器可以简单地理解为通过synchronized来实现同步的容器,比如Vector.Ha ...
- Java并发-同步容器篇
作者:汤圆 个人博客:javalover.cc 前言 官人们好啊,我是汤圆,今天给大家带来的是<Java并发-同步容器篇>,希望有所帮助,谢谢 文章如果有问题,欢迎大家批评指正,在此谢过啦 ...
- Java并发编程:并发容器ConcurrentHashMap
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- Java并发编程之并发容器
解决并发情况下的容器线程安全问题的.给多线程环境准备一个线程安全的容器对象. 线程安全的容器对象: Vector, Hashtable.线程安全容器对象,都是使用 synchronized 方法实现的 ...
- JAVA基础(9)——容器(3)——并发容器
转载:http://blog.csdn.net/weitry/article/details/52964509 JAVA基础系列规划: JAVA基础(1)——基本概念 JAVA基础(2)——数据类型 ...
- 多线程六 同步容器&并发容器
同步容器(使用的是synchronized,并且不一定是百分百安全) 本篇续 -- 线程之间的通信 ,介绍java提供的并发集合,既然正确的使用wait和notify比较困难,java平台为我们提供了 ...
随机推荐
- [20140829]spinlock导致cpu居高不下
背景: 出现cpu高于常规的告警 排查: 1.开跟踪,没有发现cup特别高的查询 2.查看内核cpu使用量,看是否是sql server 端引起 3.查看负荷,是否负荷特别高这里使用 batch re ...
- mongodb的备份
转载请附原文链接:http://www.cnblogs.com/wingsless/p/5672057.html mongodb现在为止还是没有像XtraBackup这样好用的备份工具,因此一般来说会 ...
- JUnit4生命周期
- wc
$wc [-lwc] filename统计的文件的信息,缺省参数会按照lwc的顺序输出全部三种信息 -l统计文件的行数 -w统计文件的字数,字以空格和换行符分隔 -c统计文件的字符数,包括换行等 例子 ...
- 获取下拉框的value和值
jsp: <td class="formItem_content"> <select name="label" id = "labe ...
- 关于TreeView的选中事件
在使用TreeView的选中事件时,发现,SelectAfter在第一次选中时触发,你再次点击时这个事件并不能引发它.所以找了找,发现有另两种解决办法. 最好的就是使用:NodeMouseClick, ...
- Python 标准异常
异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Exception 常规错误的 ...
- MMORPG大型游戏设计与开发(客户端架构 part9 of vegine)
时间在人们的生活中是多么重要的东西,如果打乱了时间,不知道这个时间会成什么样子.在客户端中,自然也有时间模块,因为不同的时间可能会处理不同的事情,特别是在追求高度自由化的同时,时间也成为了一个很重要的 ...
- POJ1065Wooden Sticks[DP LIS]
Wooden Sticks Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 21902 Accepted: 9353 De ...
- jsonobject 遍历 org.json.JSONObject
import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; public static ...