本文已参与「新人创作礼」活动,一起开启掘金创作之路。
我们都看过这些集合的源码(如果没有那就看看吧),每个方法都没有加锁,显然都是线程不安全的。话又说过来,如果他们安全了也就没第二问了。在集合中 Vector 和 HashTable 倒是线程安全的。你打开源码会发现其实就是把各自核心方法添加上了synchronized 关键字。
Collections 工具类提供了相关的 API,可以让上面那 3 个不安全的集合变为安全的。
| 1. | Collections.synchronizedCollection(c) |
|---|---|
| 2. | Collections.synchronizedList(list) |
| 3. | Collections.synchronizedMap(m) |
| 4. | Collections.synchronizedSet(s) |
上面几个函数都有对应的返回值类型,传入什么类型返回什么类型。打开源码其实实现原理非常简单,就是将集合的核心方法添加上了 synchronized 关键字。
HashTable 为什么是线程安全呢?
HashTable里使用的是synchronized关键字,这其实是对对象加锁,锁住的都是对象整体,当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。
ConcurrentHashMap对HashTable的优化如下:
ConcurrentHashMap算是对上述问题的优化,其构造函数如下,默认传入的是16,0.75,16。
ConcurrentHashMap引入了分割(Segment),上面代码中的最后一行其实就可以理解为把一个大的Map拆分成N个小的HashTable,在put方法中,会根据hash(paramK.hashCode())来决定具体存放进哪个Segment,如果查看Segment的put操作,我们会发现内部使用的同步
机制是基于lock操作的,这样就可以对Map的一部分(Segment)进行上锁,这样影响的只是将要放入同一个Segment的元素的put操作,保证同步的时候,锁住的不是整个Map(HashTable就是这么做的),相对于HashTable提高了多线程环境下的性能,因此HashTable已经被淘汰了。