JUC
线程安全的集合类
线程安全集合列可以分为三大类:
1.遗留的线程安全集合类:Hashtable,Vector
Hashtable(Since: JDK1.0)中的所有方法都是加了synchronized的锁(并发度很低)。
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
2.使用Collections装饰的线程安全集合,如:
- Collections.synchronizedCollection
- Collections.synchronizedList
- Collections.synchronizedMap
- Collections.synchronizedSet
- Collections.synchronizedNavigableMap
- Collections.synchronizedNavigableSet
- Collections.synchronizedSortedMap
- Collections.synchronizedSortedSet
使用Collections类的方法装饰,是利用装饰器模式,通过一个Collections的内部同步类装饰所需要操作的容器,以synchronizedMap(Map<k,v> m)为例,返回的是SynchronizedMap对象(SynchronizedMap实现了Map接口),SynchronizedMap对象有一个final Object mutex;//Object on which to synchronize 属性,该属性为同步锁,还有一个属性为private final Map<K,V> m;//Backing Map,该属性为所需要同步的容器。synchronizedMap对map的所有方法重新,在调用所有方法上都使用synchronized(mutex)加锁。
总结,所以Collections类的装饰也是在每个方法的调用加了synchronized锁(并发度依旧不高)
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
return new SynchronizedMap<>(m);
}
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();}
}
...
}
3.java.util.concunrrent.*
重点介绍java.util.concurrent.*下的线程安全集合类,可以发现他们有桂略,里面包含三类关键词:Blocking、CopyOnWrite、Concurrent
-
Blocking大部分实现基于锁,并提供用来阻塞的方法
-
CopyOnWrite之类容器修改开销相对较重(适用于读多写少的场景,修改的开销相对较重)
-
Concurrent类型的容器
-
内部很多操作使用cas优化,一般可以提供较高吞吐量
-
弱一致性
- 遍历时弱一致性,例如,当利用迭代器遍历时,如果容器发生修改,迭代器仍然可以继续进行遍历,这是内容是旧的
- 求大小弱一致性,size操作未必是100%准确的
- 读取弱一致性
遍历时如果发生了修改,对于非安全容器来讲,使用fail-fast机制也就是让遍历立即失败,抛出ConcurrentModificationException,不再继续遍历。
对于线程安全的容器,并发情况下遍历不会失败,采用的机制是fail-safe。
-