1.HashSet是基于HashMap实现的,所以具有唯一、无序、非线程安全的特点。key是set里面的值,value是同一个Object对象 “PRESENT “
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
//构造方法
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
/**
* Constructs a new set containing the elements in the specified
* collection. The <tt>HashMap</tt> is created with default load factor
* (0.75) and an initial capacity sufficient to contain the elements in
* the specified collection.
*
* @param c the collection whose elements are to be placed into this set
* @throws NullPointerException if the specified collection is null
*/
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* the specified initial capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* the specified initial capacity and default load factor (0.75).
*
* @param initialCapacity the initial capacity of the hash table
* @throws IllegalArgumentException if the initial capacity is less
* than zero
*/
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
/**
* Constructs a new, empty linked hash set. (This package private
* constructor is only used by LinkedHashSet.) The backing
* HashMap instance is a LinkedHashMap with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @param dummy ignored (distinguishes this
* constructor from other int, float constructor.)
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
2.非线程安全
因为HashMap是非线程安全的,导致HashSet也是非线程安全的。
证明:
public class TestHashSet {
static class TestThread extends Thread {
private Set<Integer> set;
private int start = -1;
private int end = -1;
public TestThread(Set<Integer> set, int start, int end) {
this.set = set;
this.start = start;
this.end = end;
}
public void run() {
for (int i = start; i < end; i++) {
set.add(i);
}
}
}
public static void main(String... args) throws Exception {
//线程不安全的HashSet
Set<Integer> set = new HashSet<Integer>();
//Set<Integer> set = Collections.synchronizedSet(new HashSet<Integer>());
//Set<Integer> set = new ConcurrentSkipListSet<Integer>();
//Set<Integer> set = new CopyOnWriteArraySet<Integer>();
new TestThread(set, 0, 25).start();
new TestThread(set, 25, 50).start();
Thread.sleep(1000);//等待线程装载数据完毕再进行下一步
//如果线程安全的话,value应该涵盖了0-49
for (int i = 0; i < 50; i++) {
boolean find = false;
for (Integer obj : set) {
if (obj == i) {
find = true;
break;
}
}
if (!find) {
System.out.println(i + "没有了");
}
}
System.out.println("size=" + set.size());
System.out.println(set);
}
}
运行结果:
0没有了
1没有了
2没有了
3没有了
8没有了
size=50
[4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 16, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 34, 35, 32, 33, 38, 39, 36, 37, 42, 43, 40, 41, 46, 47, 44, 45, 49, 48]
所以多线程环境下,一定要注意合理使用HashSet,否则数据丢失了都不知道。
3.创建线程安全的set
Set<Integer> synchronizedSet= Collections.synchronizedSet(new HashSet<Integer>());
Set<Integer> concurrentSkipListSet= new ConcurrentSkipListSet<Integer>();
Set<Integer> copyOnWriteArraySet= new CopyOnWriteArraySet<Integer>();
可以代入到上面的程序里看看运行效果。