Manufacturers face questions: We know that Set is not thread-safe, please write an insecure coding case and gives the solution?
1, Set thread insecurity problems
import java.util.HashSet;
import java.util.Set;
java.util.UUID import;
public class ContainerNotSafeDemoTwo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString());
System.out.println(set.toString());
}, "T1").start();
}
}
}
Program execution results are as follows: Abnormal reported java.util.ConcurrentModificationException
2, produced by reason ConcurrentModificationException
A thread is writing, another thread came to seize resources, will result in inconsistent data, and then reported concurrent modification exception.
3, Set thread safe solution
(1) A first solution
Creating collections Use Collections synchronization tools
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
java.util.UUID import;
public class ContainerSafeSetDemoOne {
public static void main(String[] args) {
Set<String> set = Collections.synchronizedSet(new HashSet<>());
for (int i = 0; i < 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString());
System.out.println(set.toString());
}, String.valueOf(i)).start();
}
}
}
(2) The second solution
Alternatively CopyOnWriteArraySet concurrent programming class HashSet
import java.util.Set;
java.util.UUID import;
import java.util.concurrent.CopyOnWriteArraySet;
public class ContainerSafeSetDemoTwo {
public static void main(String[] args) {
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString());
System.out.println(set.toString());
}, String.valueOf(i)).start();
}
}
}
CopyOnwriteArraySet container vessel that is copy-on-write. Element added to a container when the container is not directly to the current Object [] is added, but the first current container Object [] for Copy, a copy of a new container object [] newElements, and then to a new container Object [] the newElements Lane added element, after adding an element, then references to the new container setArray (newElements) the original container; the benefits of doing so is concurrent reading of CopyOnWrite container without the need to lock, because the current container does not add any element . Therefore, the container is also a separate read and write CopyOnWrite thought, reading and writing is different containers.
public boolean add(E e) {
return al.addIfAbsent(e);
}
/**
* 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] = a;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}