一、HashSet

HashSet是基于HashMap实现的,因为HashMap本身是线程不安全的,所以HashMap就是线程不安全的,

简单看下HashSet的源码

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;
	//真正存元素的map,key是要存进set的元素,value是Object
    private transient HashMap<E,Object> map;
    
    public boolean add(E e) {
    	//添加元素时往内部的map中放入
        return map.put(e, PRESENT)==null;
    }
}

二、线程安全的set

2.1 java.util.Collections#synchronizedSet(java.util.Set)

这个工具方法接收一个set集合,对它进行包装,让每个方法都被Synchronized修饰,用这种方式保证线程安全。

因为锁对象是集合对象本身,所以存和取的方法不能同时执行,性能较低。

2.2 CopyOnWriteArraySet

这个set基于CopyOnWriteArrayList实现,保证线程安全

public class CopyOnWriteArraySet<E> extends AbstractSet<E>
        implements java.io.Serializable {
    private static final long serialVersionUID = 5457747651344034263L;
	
	//内部持有一个CopyOnWriteArrayList
    private final CopyOnWriteArrayList<E> al;
    
    //添加方法,调用的是CopyOnWriteArrayList的方法
    public boolean add(E e) {
        return al.addIfAbsent(e);
    }
}

再继续看下CopyOnWriteArrayList#addIfAbsent方法,这个方法一定是线程安全的

public boolean addIfAbsent(E e) {
    //先获取存元素的数组
    Object[] snapshot = getArray();
    //查找当前集合中是否有e
    return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
    //添加
    addIfAbsent(e, snapshot);
}

private boolean addIfAbsent(E e, Object[] snapshot) {
    final ReentrantLock lock = this.lock;
    //加锁
    lock.lock();
    try {
        //获取最新的数组
        Object[] current = getArray();
        //新数组的长度
        int len = current.length;
        //判断数组是否发生了变化
        if (snapshot != current) {
            // Optimize for lost race to another addXXX operation
            // 找出最短的长度
            int common = Math.min(snapshot.length, len);
            //这个for循环是一种针对判断效率的优化,如果在0-common中能找到e就返回false
            //因为这个snapshot在调用当前方法前已经检查过了,所以循环中current[i] = snapshot[i]的时候
            // snapshot[i]一定不等于e
            for (int i = 0; i < common; i++)
                if (current[i] != snapshot[i] && eq(e, current[i]))
                    return false;
            //查询current中的剩余元素
            if (indexOf(e, current, common, len) >= 0)
                return false;
        }
        //走到这里表示当前集合没有,需要添加元素
        Object[] newElements = Arrays.copyOf(current, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        //释放锁
        lock.unlock();
    }
}