同步类容器和并发类容器

来源:互联网 发布:软件著作权申请表下载 编辑:程序博客网 时间:2024/05/16 07:14

同步类容器都是线程安全的,但在某些场景下可能需要加锁来保护复合操作,复合类操作 如:迭代(反复访问原始,遍历容器中所有的元素)、跳转(根据指定的顺序找到当前元素的下一个元素)、以及条件运算。这些复合操作在多线程并发得修改容器的时候可以会表现出意外的行为,最经典的就是 ConcurrentModificationException ,原因是当容易迭代过程中,被并发的修改了内容。这是由于早期迭代器设计的时候并没有考虑到并发修改的问题。

同步类容器 :Vector 、hashTable.这些容器的同步功能都是有JDK的Collections.synchronized等工厂方法去创建实现的,其底层的机制无非是使用了传统的synchronized关键字对每个公共的方法都进行同步,这使得每次只有一个线程访问容器的状态。这明显不满足我们今天互联网时代高并发的需求,在保证线程安全的同时,也必须有足够好的性能。


1、同步类容器 

public class Tickets {public static void main(String[] args) {// 初始化火车票池并添加火车票:避免线程同步可采用Vector替代ArrayList HashTable替代HashMapfinal Vector<String> tickets = new Vector<String>();// Map<String, String> map = Collections.synchronizedMap(new// HashMap<String, String>());for (int i = 1; i <= 1000; i++) {tickets.add("火车票" + i);}for (Iterator iterator = tickets.iterator(); iterator.hasNext();) {String string = (String) iterator.next();tickets.remove(20);}}}

Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.Vector$Itr.checkForComodification(Vector.java:1156)at java.util.Vector$Itr.next(Vector.java:1133)at com.eshine.base.coll012.Tickets.main(Tickets.java:26)
这里并没有启动2个线程,只是简单的在往Vector加入元素的后,同时遍历它并移出第20个元素。

在代码注释里面:Collections.synchronizedMap(new HashMap<String, String>()); 我们知道,HashMap并不是线程安全的。当时我们使用了:Collections.synchronizedMap()对其进行包裹,那么它就是线程安全的了


2、并发类容器

同步内容器的状态都是串行化的,他的虽然是线程安全,当时降低了并发性。在多线程环境的时候,严重降低了应用程序的吞吐量。

并发类容器则是针对并发而设计的,使用了ConcurrentHashMap代替给予散列的传统的HashTable,而且,ConncurrentHashMap中,添加了一些常见复核操作的支持,以及使用了CopyOnWriteArrayList代替Voctory,并发的CopyOnWriteArraySet,以及并发的Queue,ConcurrentLinkedQueue和LinkedBlockingQueue,前者是高性能的队列,后者是以阻塞形式的队列,具体实现Queue还有很多,例如ArrayBlockingQueue、PriorityBlockingQueue、SynchrousQueue等等

2.1、ConcurrentMap

ConcurrentMap有2个重要的实现ConcurrentHashMap和ConcurrentSkipMap(支持并发排序功能,弥补ConcurrentHashMap),

我们可以吧ConcurrentHashMap理解为以前的HashMap或者Hashtable,ConcurrentSkipMap理解为TreeMap.ConcurrentHashMap的底层实现方式是:在ConcurrentHashMap有‘segment’的概念,意思是段,他把hashTable分成了16个段(减小锁的的粒度),并在线程进行访问的时候,将某一个段锁住,这样就实现了多线程可以访问ConcurrentHashMap了

public class UseConcurrentMap {public static void main(String[] args) {ConcurrentHashMap<String, Object> chm = new ConcurrentHashMap<String, Object>();chm.put("k1", "v1");chm.put("k2", "v2");chm.put("k3", "v3");chm.putIfAbsent("k4", "vvvv");//System.out.println(chm.get("k2"));//System.out.println(chm.size());for(Map.Entry<String, Object> me : chm.entrySet()){System.out.println("key:" + me.getKey() + ",value:" + me.getValue());}}}

2.2、CopyOnWrite(读多写少)

CopyOnWrite有2种CopyOnWriteArrayList、CopyOnWriteArraySet,他们可以在非常多的并发场景中使用

CopyOnWrite即写时复制的容器,通俗的讲就是当我们往一个容器中添加元素的时候,不直接往里面添加,而是先把当前容器copy一个,然后往新的容器中添加,添加完成之后,再将原容器的的引用指向新的容器。这样做的好处就是我们可以在CopyOnWrite容器中进行并发的读,而不需要加锁,因为当前容器不会添加任何元素,所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器

public class UseCopyOnWrite {public static void main(String[] args) {CopyOnWriteArrayList<String> cwal = new CopyOnWriteArrayList<String>();CopyOnWriteArraySet<String> cwas = new CopyOnWriteArraySet<String>();}}


总结:以上的并发类容器,我们平常使用hashmap、list如何使用,这些类就如何使用,没有什么太大的变化









0 0
原创粉丝点击