欢迎大家关注 github.com/hsfxuebao/j… ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈
4、集合框架
我们知道ArrayList是线程不安全,请编码一个不安全的案例并给出解决方案
4.1、ArrayList 不安全
我们知道ArrayList是线程不安全,请编码一个不安全的案例并给出解决方案
-
代码
public class ContainerNotSafeDemo {
/* * 1 故障现象 * java.util.ConcurrentModificationException * * 2 导致原因 * 并发争抢修改导致,参考我们的花名册签名情况。 * 一个人正在写入,另一个同学过来抢夺,导致数据不一致异常。并发修改异常。 * * */ public static void main(String[] args) { listNotSafe(); } private static void listNotSafe() { List<String> list=new ArrayList<>(); // java.util.ConcurrentModificationException for (int i = 1; i <= 30; i++) { new Thread(() -> { list.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(Thread.currentThread().getName() + "\t" + list); }, String.valueOf(i)).start(); } }} 12345678910111213141516171819202122232425262728293031323334
-
程序运行结果:由于 ArrayList 类的 add() 方法没有加锁,所以存在多线程并发安全问题
java.util.ConcurrentModificationException at java.util.ArrayListItr.next(ArrayList.java:851) at java.util.AbstractCollection.toString(AbstractCollection.java:461) at java.lang.String.valueOf(String.java:2994) at java.lang.StringBuilder.append(StringBuilder.java:131) at com.Heygo.ContainerNotSafeDemo.lambda0(ContainerNotSafeDemo.java:26) at java.lang.Thread.run(Thread.java:748) 12345678
解决问题 ArrayList 线程不安全
- 使用
new Vector<>();(ArrayList所有方法加synchronized,太重)。 - 使用
Collections.synchronizedList(new ArrayList<>());转换成线程安全类。 - 使用
new java.concurrent.CopyOnWriteArrayList<>();(推荐)。
CopyOnWriteArrayList
CopyOnWriteArrayList 写时复制
- 写时复制:CopyOnWrite容器,即写时复制的容器。
- 往一个容器添加元素的时候,不直接往当前容器 Object[] 添加,而是先将当前 Object[] 进行Copy,复制出一个新的容器Object[] newElements,然后新的容器Object[] newElements里添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray(newElements)
- 这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。
- 所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
CopyOnWriteArrayList 代码示例
-
代码:使用 CopyOnWriteArrayList 集合类,保证 ArrayList 并发修改安全性的同时,也保证了并发读取的效率
public class ContainerNotSafeDemo {
/* * 1 故障现象 * java.util.ConcurrentModificationException * * 2 导致原因 * 并发争抢修改导致,参考我们的花名册签名情况。 * 一个人正在写入,另一个同学过来抢夺,导致数据不一致异常。并发修改异常。 * * 3 解决方案 * 3.1 new Vector<>(); * 3.2 集合工具类:Collections.synchronizedList(new ArrayList<>()); * 3.3 new CopyOnWriteArrayList<>() * 写时复制:CopyOnWrite容器即写时复制的容器。 * 往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前object[]进行Copy, * 复制出一个新的容器Object[] newElements,然后新的容器Object[] newElements里添加元素, * 添加完元素之后,再将原容器的引用指向新的容器setArray(newElements); * 这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。 * 所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。 * * 4 优化建议(同样的错误不犯两次) * * */ public static void main(String[] args) { listNotSafe(); } private static void listNotSafe() { List<String> list = new CopyOnWriteArrayList<>(); for (int i = 1; i <= 30; i++) { new Thread(() -> { list.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(Thread.currentThread().getName() + "\t" + list); }, String.valueOf(i)).start(); } }} 12345678910111213141516171819202122232425262728293031323334353637383940414243444546
-
程序运行结果
5 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72] 8 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9] 10 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9] 2 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9] 3 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72] 12 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02] 7 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e] 4 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72] 15 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a] 14 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e] 13 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b] 1 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e] 22 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d, a76fe96a] 11 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e] 6 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803] 9 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64] 27 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d, a76fe96a, e28f0c36, ee151ef4, 1ce730cc, 5807293f, 8163070f] 26 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d, a76fe96a, e28f0c36, ee151ef4, 1ce730cc, 5807293f] 25 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d, a76fe96a, e28f0c36, ee151ef4, 1ce730cc] 24 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d, a76fe96a, e28f0c36, ee151ef4] 23 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d, a76fe96a, e28f0c36] 21 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d] 20 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143] 19 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a] 18 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e] 17 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9] 16 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3] 30 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d, a76fe96a, e28f0c36, ee151ef4, 1ce730cc, 5807293f, 8163070f, 8bc1cbfc, 58caaadd] 29 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d, a76fe96a, e28f0c36, ee151ef4, 1ce730cc, 5807293f, 8163070f, 8bc1cbfc, 58caaadd, ce11ccb2] 28 [ce629c0f, 195253cd, 9d98dc22, b3ed3b72, 1542d43e, 1494f2e9, aa7e9f64, 413cf9d9, ce7e5748, 1feaa74e, 6d40a803, 5fa45f02, 86971d8b, 14886d8e, 232c6e3a, ecf34ff3, 9aa964b9, a4cf1f6e, 5427a83a, 250c0143, 4c32f82d, a76fe96a, e28f0c36, ee151ef4, 1ce730cc, 5807293f, 8163070f, 8bc1cbfc]
12345678910111213141516171819202122232425262728293031
ArrayList 源码分析
-
初始化时,构造了一个空的
Object[]数组/** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }12345678910111213
-
ArrayList 中使用
Object[]数组存放数据/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access1234567
-
第一次添加元素时,初始化 Object[] 数组的大小为
DEFAULT_CAPACITY = 10/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } /** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10; private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }123456789101112131415161718192021222324
-
扩容操作
-
每次扩容为旧容量的 1.5 倍
-
ArrayList 最大容量为
Integer.MAX_VALUE - 8 -
使用
Arrays.copyOf()方法扩容,并将将原来数组中的值拷贝到新数组中private void ensureExplicitCapacity(int minCapacity) { modCount++;
// overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity);}
/**
- The maximum size of array to allocate.
- Some VMs reserve some header words in an array.
- Attempts to allocate larger arrays may result in
- OutOfMemoryError: Requested array size exceeds VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
- Increases the capacity to ensure that it can hold at least the
- number of elements specified by the minimum capacity argument.
- @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } 123456789101112131415161718192021222324252627282930313233
-
Collections. synchronizedList() 源码
-
Collections.synchronizedList()方法:由于 ArrayList 实现了 RandomAccess 接口,所以在方法内部创建了一个 SynchronizedRandomAccessList 的实例/** * Returns a synchronized (thread-safe) list backed by the specified * list. In order to guarantee serial access, it is critical that * <strong>all</strong> access to the backing list is accomplished * through the returned list.<p> * * It is imperative that the user manually synchronize on the returned * list when iterating over it: * <pre> * List list = Collections.synchronizedList(new ArrayList()); * ... * synchronized (list) { * Iterator i = list.iterator(); // Must be in synchronized block * while (i.hasNext()) * foo(i.next()); * } * </pre> * Failure to follow this advice may result in non-deterministic behavior. * * <p>The returned list will be serializable if the specified list is * serializable. * * @param <T> the class of the objects in the list * @param list the list to be "wrapped" in a synchronized list. * @return a synchronized view of the specified list. */ public static <T> List<T> synchronizedList(List<T> list) { return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list) : new SynchronizedList<>(list)); }12345678910111213141516171819202122232425262728293031
-
SynchronizedRandomAccessList 类是 Collections 类的静态内部类
-
SynchronizedRandomAccessList 的父类为 SynchronizedList 类
-
super(list);表示调用父类 SynchronizedList 的构造方法static class SynchronizedRandomAccessList extends SynchronizedList implements RandomAccess {
SynchronizedRandomAccessList(List<E> list) { super(list); }1234567
-
SynchronizedList 类也是 Collections 类的静态内部类
-
SynchronizedList 类的父类是 SynchronizedCollection 类
-
super(list);表示调用父类 SynchronizedCollection 的构造方法 -
SynchronizedList 内部维护了 ArrayList 的引用:
this.list = list;static class SynchronizedList extends SynchronizedCollection implements List { private static final long serialVersionUID = -7754090372962971524L;
final List<E> list; SynchronizedList(List<E> list) { super(list); this.list = list; }1234567891011
-
SynchronizedCollection 类也是 Collections 类的静态内部类
-
在 SynchronizedCollection 内部维护了 ArrayList 的引用:
this.c = Objects.requireNonNull(c); -
通过
final Object mutex这把锁,给集合中的所有方法都加上锁,保证多线程并发的安全性static class SynchronizedCollection implements Collection, 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) { this.c = Objects.requireNonNull(c); mutex = this; } SynchronizedCollection(Collection<E> c, Object mutex) { this.c = Objects.requireNonNull(c); this.mutex = Objects.requireNonNull(mutex); } public int size() { synchronized (mutex) {return c.size();} } public boolean isEmpty() { synchronized (mutex) {return c.isEmpty();} } public boolean contains(Object o) { synchronized (mutex) {return c.contains(o);} } public Object[] toArray() { synchronized (mutex) {return c.toArray();} } public <T> T[] toArray(T[] a) { synchronized (mutex) {return c.toArray(a);} } public Iterator<E> iterator() { return c.iterator(); // Must be manually synched by user! } public boolean add(E e) { synchronized (mutex) {return c.add(e);} } public boolean remove(Object o) { synchronized (mutex) {return c.remove(o);} } public boolean containsAll(Collection<?> coll) { synchronized (mutex) {return c.containsAll(coll);} } public boolean addAll(Collection<? extends E> coll) { synchronized (mutex) {return c.addAll(coll);} } public boolean removeAll(Collection<?> coll) { synchronized (mutex) {return c.removeAll(coll);} } public boolean retainAll(Collection<?> coll) { synchronized (mutex) {return c.retainAll(coll);} } public void clear() { synchronized (mutex) {c.clear();} } public String toString() { synchronized (mutex) {return c.toString();} } // Override default methods in Collection @Override public void forEach(Consumer<? super E> consumer) { synchronized (mutex) {c.forEach(consumer);} } @Override public boolean removeIf(Predicate<? super E> filter) { synchronized (mutex) {return c.removeIf(filter);} } @Override public Spliterator<E> spliterator() { return c.spliterator(); // Must be manually synched by user! } @Override public Stream<E> stream() { return c.stream(); // Must be manually synched by user! } @Override public Stream<E> parallelStream() { return c.parallelStream(); // Must be manually synched by user! } private void writeObject(ObjectOutputStream s) throws IOException { synchronized (mutex) {s.defaultWriteObject();} }} 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
CopyOnWriteArrayList 源码分析
-
CopyOnWriteArrayList 内部维护了两个重要成员变量:
- ReentrantLock 锁:保证多线程并发修改的安全性
- Object[] array 数组:使用 volatile 修饰,保证内存的可见性
public class CopyOnWriteArrayList implements List, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8673264195747942595L;
/** The lock protecting all mutators */ final transient ReentrantLock lock = new ReentrantLock(); /** The array, accessed only via getArray/setArray. */ private transient volatile Object[] array; /** * Gets the array. Non-private so as to also be accessible * from CopyOnWriteArraySet class. */ final Object[] getArray() { return array; } /** * Sets the array. */ final void setArray(Object[] a) { array = a; } /** * Creates an empty list. */ public CopyOnWriteArrayList() { setArray(new Object[0]); }12345678910111213141516171819202122232425262728293031
-
添加元素:
-
上锁{
-
数组长度扩容 1 个元素,将旧元素拷贝至新数组与中,将新元素放在数组末尾
-
修改
rivate transient volatile Object[] array;的引用 -
}解锁
/**
- Appends the specified element to the end of this list.
- @param e element to be appended to this list
- @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } } 1234567891011121314151617181920
-
-
由于采用了读写分离,所以读取集合无需加锁,提高了读的并发性
public String toString() { return Arrays.toString(getArray()); } 123
4.2、HashSet 不安全
演示 HashSet 线程不安全
-
代码
public class ContainerNotSafeDemo { public static void main(String[] args) { setNoSafe(); }
private static void setNoSafe() { Set<String> set=new HashSet<>(); for (int i = 1; i <= 30; i++) { new Thread(() -> { set.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(Thread.currentThread().getName() + "\t" + set); }, String.valueOf(i)).start(); } }} 12345678910111213141516171819202122
-
程序运行结果:
java.util.ConcurrentModificationExceptionjava.util.ConcurrentModificationException at java.util.HashMapKeyIterator.next(HashMap.java:1461) at java.util.AbstractCollection.toString(AbstractCollection.java:461) at java.lang.String.valueOf(String.java:2994) at java.lang.StringBuilder.append(StringBuilder.java:131) at com.Heygo.ContainerNotSafeDemo.lambda2(ContainerNotSafeDemo.java:71) at java.lang.Thread.run(Thread.java:748) 12345678
解决 HashSet 线程不安全问题
- 使用 CollectionssynchronizedSet() 方法将 HashSet 转为线程安全版本
- 使用 CopyOnWriteArraySet 类:读写分离
CopyOnWriteArraySet 代码示例
-
代码
/**
-
@ClassName ContainerNotSafeDemo
-
@Description TODO
-
@Author Heygo
-
@Date 2020/8/7 21:35
-
@Version 1.0 */ public class ContainerNotSafeDemo { public static void main(String[] args) { setNoSafe(); }
private static void setNoSafe() { Set set = new CopyOnWriteArraySet<>(); for (int i = 1; i <= 30; i++) { new Thread(() -> { set.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(Thread.currentThread().getName() + "\t" + set); }, String.valueOf(i)).start(); } } } 12345678910111213141516171819202122
-
-
程序运行结果
1 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb] 7 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a] 16 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177] 18 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e] 15 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a] 21 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e] 4 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7] 3 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7] 2 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7] 13 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7] 24 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e, f995ef22, 866bc698, 22177284, 6252e23d] 8 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9] 14 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9] 30 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e, f995ef22, 866bc698, 22177284, 6252e23d, 85e01c3e, 0edf78f9, a0c65913] 5 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d] 11 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d] 9 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb] 12 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24] 26 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e, f995ef22, 866bc698, 22177284, 6252e23d, 85e01c3e, 0edf78f9, a0c65913, 9ae99682, 84b58b16] 25 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e, f995ef22, 866bc698, 22177284, 6252e23d, 85e01c3e, 0edf78f9, a0c65913, 9ae99682] 29 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e, f995ef22, 866bc698, 22177284, 6252e23d, 85e01c3e, 0edf78f9, a0c65913, 9ae99682] 28 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e, f995ef22, 866bc698, 22177284, 6252e23d, 85e01c3e, 0edf78f9] 27 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e, f995ef22, 866bc698, 22177284, 6252e23d, 85e01c3e] 22 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e, f995ef22, 866bc698] 23 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7, 3f6ded3e, f995ef22] 20 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89, 73bd78e7] 19 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6, 23fbb23e, ec60cb89] 17 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a, 25b9d177, e5567ae6] 6 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb] 10 [d9f8ebbc, 1d6205eb, 836575a9, ce40bd87, 7bacd0f6, 57d5347f, e1676b1c, c10c5256, 247ff963, 3a5b3feb, ce846b2d, 9e050a24, 0e7e56e9, bf76ebc7, 6072428a] 123456789101112131415161718192021222324252627282930
HashSet 源码分析
-
HashSet 的构造器:底层维护了一个负载因子为 0.75 的 HashMap
public class HashSet extends AbstractSet implements Set, Cloneable, java.io.Serializable { static final long serialVersionUID = -5024744406713321676L;
private transient HashMap<E,Object> map; // 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<>(); }123456789101112131415161718
-
add() 方法:
-
key 为待添加的元素
-
value 统一为
private static final Object PRESENT = new Object();/**
- Adds the specified element to this set if it is not already present.
- More formally, adds the specified element e to this set if
- this set contains no element e2 such that
- (e==null ? e2==null : e.equals(e2)).
- If this set already contains the element, the call leaves the set
- unchanged and returns false.
- @param e element to be added to this set
- @return true if this set did not already contain the specified
- element */ public boolean add(E e) { return map.put(e, PRESENT)==null; } 123456789101112131415
-
Collections.synchronizedSet() 源码分析
-
Collections.synchronizedSet()方法创建了一个 synchronizedSet 类的实例/** * Returns a synchronized (thread-safe) set backed by the specified * set. In order to guarantee serial access, it is critical that * <strong>all</strong> access to the backing set is accomplished * through the returned set.<p> * * It is imperative that the user manually synchronize on the returned * set when iterating over it: * <pre> * Set s = Collections.synchronizedSet(new HashSet()); * ... * synchronized (s) { * Iterator i = s.iterator(); // Must be in the synchronized block * while (i.hasNext()) * foo(i.next()); * } * </pre> * Failure to follow this advice may result in non-deterministic behavior. * * <p>The returned set will be serializable if the specified set is * serializable. * * @param <T> the class of the objects in the set * @param s the set to be "wrapped" in a synchronized set. * @return a synchronized view of the specified set. */ public static <T> Set<T> synchronizedSet(Set<T> s) { return new SynchronizedSet<>(s); }1234567891011121314151617181920212223242526272829
-
SynchronizedSet 类是 Collections 的静态内部类
-
SynchronizedSet 类的父类是 SynchronizedCollection 类
-
super(s);调用父类构造器static class SynchronizedSet extends SynchronizedCollection implements Set { private static final long serialVersionUID = 487447009682186044L;
SynchronizedSet(Set<E> s) { super(s); }12345678
-
SynchronizedSet 和 SynchronizedList 都继承自 SynchronizedCollection 类,均是通过 mutex 这把锁解决了多线程并发修改的安全问题
static class SynchronizedCollection implements Collection, 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) { this.c = Objects.requireNonNull(c); mutex = this; } SynchronizedCollection(Collection<E> c, Object mutex) { this.c = Objects.requireNonNull(c); this.mutex = Objects.requireNonNull(mutex); } public int size() { synchronized (mutex) {return c.size();} } public boolean isEmpty() { synchronized (mutex) {return c.isEmpty();} } public boolean contains(Object o) { synchronized (mutex) {return c.contains(o);} } public Object[] toArray() { synchronized (mutex) {return c.toArray();} } public <T> T[] toArray(T[] a) { synchronized (mutex) {return c.toArray(a);} } public Iterator<E> iterator() { return c.iterator(); // Must be manually synched by user! } public boolean add(E e) { synchronized (mutex) {return c.add(e);} } public boolean remove(Object o) { synchronized (mutex) {return c.remove(o);} } public boolean containsAll(Collection<?> coll) { synchronized (mutex) {return c.containsAll(coll);} } public boolean addAll(Collection<? extends E> coll) { synchronized (mutex) {return c.addAll(coll);} } public boolean removeAll(Collection<?> coll) { synchronized (mutex) {return c.removeAll(coll);} } public boolean retainAll(Collection<?> coll) { synchronized (mutex) {return c.retainAll(coll);} } public void clear() { synchronized (mutex) {c.clear();} } public String toString() { synchronized (mutex) {return c.toString();} } // Override default methods in Collection @Override public void forEach(Consumer<? super E> consumer) { synchronized (mutex) {c.forEach(consumer);} } @Override public boolean removeIf(Predicate<? super E> filter) { synchronized (mutex) {return c.removeIf(filter);} } @Override public Spliterator<E> spliterator() { return c.spliterator(); // Must be manually synched by user! } @Override public Stream<E> stream() { return c.stream(); // Must be manually synched by user! } @Override public Stream<E> parallelStream() { return c.parallelStream(); // Must be manually synched by user! } private void writeObject(ObjectOutputStream s) throws IOException { synchronized (mutex) {s.defaultWriteObject();} }} 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
CopyOnWriteArraySet 源码分析
-
CopyOnWriteArraySet 内部维护了一个 CopyOnWriteArrayList 实例,典型的挂羊皮卖狗肉
public class CopyOnWriteArraySet extends AbstractSet implements java.io.Serializable { private static final long serialVersionUID = 5457747651344034263L;
private final CopyOnWriteArrayList<E> al; /** * Creates an empty set. */ public CopyOnWriteArraySet() { al = new CopyOnWriteArrayList<E>(); }123456789101112
-
copyOnWriteArraySet.add()方法:调用copyOnWriteArrayList.addIfAbsent()方法// CopyOnWriteArraySet 类的 add() 方法 /** * Adds the specified element to this set if it is not already present. * More formally, adds the specified element {@code e} to this set if * the set contains no element {@code e2} such that * <tt>(e==null ? e2==null : e.equals(e2))</tt>. * If this set already contains the element, the call leaves the set * unchanged and returns {@code false}. * * @param e element to be added to this set * @return {@code true} if this set did not already contain the specified * element */ public boolean add(E e) { return al.addIfAbsent(e); }12345678910111213141516
-
copyOnWriteArrayList.addIfAbsent()方法:-
获取 Object[] 数组的快照
-
将元素添加至 ArrayList(这里看不太懂)
/**
- Appends the element, if not present.
- @param e element to be added to this list, if absent
- @return {@code true} if the element was added */ public boolean addIfAbsent(E e) { Object[] snapshot = getArray(); return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false : addIfAbsent(e, snapshot); }
/**
- A version of addIfAbsent using the strong hint that given
- recent snapshot does not contain e. */ 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 (int i = 0; i < common; i++) if (current[i] != snapshot[i] && eq(e, current[i])) return false; 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(); } }
-