集合线程安全控制-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 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。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值