Vector 和 Hashtable都是古老的类,都是线程安全类。尽量少用Hashtable,Vector.
需要创建线程安全的List实现类,也无需使用Vector 实现类
需要创建线程安全的Map实现类,也无需使用Hashtable实现类。
可以使用Collections工具类把HashMap变成线程安全的。
Collections类提供了多个synchronizedXxx()方法,该方法可以将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题。
Java中常用的集合框架的实现类HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap和TreeMap都是线程不安全的。如果有多个线程试图修改它们,Collections提供了多个类方法可以把它们包装成线程同步的集合。
Collection c = Collections.synchronizedCollection(new ArrayList());
List list = Collections.synchronizedList(new ArrayList());
Set s = Collections.synchroniezedSet(new HashSet());
Map m = Collections.synchronizedMap(new HashMap());
Collections类的synchronizedXxx()方法 是怎么样确保实现线程安全的呢?
class ListHelper <E> {
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public boolean putIfAbsent(E x) {
synchronized (list) {
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
}
}
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<T>(list) :
new SynchronizedList<T>(list));
}
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList源码实现了RandomAccess,所以创建的应该是SynchronizedRandomAccessList类;
static class SynchronizedRandomAccessList<E> extends SynchronizedList<E> implements RandomAccess {
SynchronizedRandomAccessList(List<E> list) {
super(list);
}
SynchronizedRandomAccessList(List<E> list, Object mutex) {
super(list, mutex);
}
public List<E> subList(int fromIndex, int toIndex) {
synchronized(mutex) {
return new SynchronizedRandomAccessList<E>(
list.subList(fromIndex, toIndex), mutex);
}
}
static final long serialVersionUID = 1530674583602358482L;
private Object writeReplace() {
return new SynchronizedList<E>(list);
}
}
因为SynchronizedRandomAccessList这个类继承自SynchronizedList,而大部分方法都在SynchronizedList中实现了,所以源码中只包含了很少的方法,但是通过subList方法,我们可以看到这里使用的锁对象为mutex对象,而mutex是在SynchronizedCollection类中定义的,所以再看看SynchronizedCollection这个类中关于mutex的定义部分源码:
static class SynchronizedCollection<E> implements Collection<E>, Serializable {
private static final long serialVersionUID = 3053995032091335093L;
final Collection<E> c; // Backing Collection
final Object mutex; // Object on which to synchronize
SynchronizedCollection(Collection<E> c) {
if (c==null)
throw new NullPointerException();
this.c = c;
mutex = this;
}
SynchronizedCollection(Collection<E> c, Object mutex) {
this.c = c;
this.mutex = mutex;
}
}
可以看到mutex就是当前的SynchronizedCollection对象,而SynchronizedRandomAccessList继承自SynchronizedList,SynchronizedList又继承自SynchronizedCollection,所以SynchronizedRandomAccessList中的mutex也就是SynchronizedRandomAccessList的this对象。所以在ListHelper类中使用的锁list对象和SynchronizedRandomAccessList内部的锁是一致的,所以它可以实现线程安全性。 -------》这部分参考博客https://www.cnblogs.com/yaowen/p/5983136.html
public static Map m = Collections.synchronizedMap(new HashMap());
Collections.synchronizedMap()会生成一个名为SynchronizedMap的Map,,它使用委托,将自己所有的Map相关的功能交给传入的
HashMap实现,而自己则主要负责保证线程安全。
首先SynchronizedMap内包装了一个Map;
private static class SynchronizedMap<K,V> implements Map<K,V>,Serializable{
private static final long serialVersionUID = 1978198479659L;
private final Map<K,V> m; //Backing Map
final Object mutex; //Object on which to synchronize
}
通过mutex实现对这个m的互斥操作。比如,对于Map.get()方法实现如下;
public V get(Object key){
synchronized (mutex) {return m.get(key);}
}
这个包装的Map可以满足线程安全的要求,但是,它在多线程环境中的性能表现并不太算好。无论是对Map的读取或写入,都需要获取mutex的锁,这会导致所有对Map的操作全部进入等待状态,直到mutex锁可用。如果并发级别不高,一般也够用。
但是在高并发环境中,就不适合,可以使用ConcurrentHashMap。