集合线程安全控制-Collections工具类synchronizedXxx()方法
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 Mapfinal 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。