1)Hashtable中采用的锁机制(Synchronized)是一次锁住整个hash表,从而同一时刻只能由一个线程对其进行操作;
Hashtable的任何操作都会把整个表锁住,是阻塞的。优势:是总能获取最实时的更新,比如说线程A调用putAll写入大量数据,期间线程B调用get,线程B就会被阻塞,直到线程A完成putAll,因此线程B肯定能获取到线程A写入的完整数据。缺点:是所有调用都要排队,效率较低。当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间
2)ConcurrentHashMap锁的方式是稍微细粒度的。 ConcurrentHashMap将hash表分为16个桶(默认值),诸如get,put,remove等常用操作只锁当前需要用到的桶。原来只能一个线程进入,现在却能同时16个写线程进入(写线程才需要锁定,而读线程几乎不受限制,之后会提到),并发性的提升是显而易见的。
读写锁分离:惊讶的是ConcurrentHashMap的读取并发,因为在读取的大多数时候都没有用到锁定,所以读取操作几乎是完全的并发操作,而写操作锁定的粒度又非常细,比起之前又更加快速(这一点在桶更多时表现得更明显些)。只有在求size等操作时才需要锁定整个表。
ConcurrentHashMap在1.8版本里面好像都是调用native方法实现的。。。也就是说线程安全都是依靠底层硬件实现的。
优点:ConcurrentHashMap 是设计为非阻塞的。在更新时会局部锁住某部分数据,但不会把整个表都锁住。同步读取操作则是完全非阻塞的。好处是在保证合理的同步前提下,效率很高。缺点:是严格来说读取操作不能保证反映最近的更新。
3)通过将基本的功能从线程安全性中分离开来,Collections.synchronizedMap允许需要同步的用户可以拥有同步,而不需要同步的用户则不必为同步付出代价。
Map m = Collections.synchronizedMap(new HashMap()); 将线程不安全的HashMap变成线程安全的。
List l = Collections.synchronizedList(new ArrayList());
例如: Map m = Collections.synchronizedMap(new HashMap());
Set s = m.keySet(); // Needn't be in synchronized block
synchronized(m) { // Synchronizing on m, not s!
Iterator i = s.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
本文探讨了Hashtable与ConcurrentHashMap两种数据结构的锁机制差异。Hashtable采用整体锁,确保了数据的一致性但降低了并发效率;ConcurrentHashMap通过细粒度锁和读写分离策略实现了高并发访问。

2137

被折叠的 条评论
为什么被折叠?



