This is the 26th day of my participation in the August Text Challenge.More challenges in August
preface
In a multithreaded environment, many of the classes we use everyday have thread safety problems, such as ArrayList, HashSet, HashMap, so how should we handle thread problems in a multithreaded environment? What is the CAS algorithm? Is there another way to achieve thread safety besides synchronized? Optimistic locking? Pessimistic locks?
Synchronization of the container
The JUC toolkit provides thread-safe alternatives to these collection classes that are often used in everyday development.
- ArrayList
-->
CopyOnWriteArrayList--
Write copy list- HashSet
-->
CopyOnWriteArraySet--
Write copy set- HashMap
-->
ConcurrentHashMap--
Piecewise lock mapping
CopyOnWriteArrayList
The CopyOnWriteArrayList layer avoids concurrency problems in multithreaded environments by manipulating “copies”.
When a thread operates on a list, it adds a lock, makes a copy of the current object’s value, creates a new object of length +1, and points the reference address to the new ArrayList
Add () method source
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(); }}Copy the code
CopyOnWriteArraySet
This is similar to CopyOnWriteArrayList, except that the underlying data structure stores the data
The source code
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(); }}Copy the code
ConcurrentHashMap
Code sample
public class ConcurrentHashMapSample {
public static int users = 100;// The number of concurrent access users simulated at the same time
public static int downTotal = 50000; // The real total number of downloads by users
public static ConcurrentHashMap count = new ConcurrentHashMap() ;/ / counter
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(users);
for(int i = 0 ; i < downTotal ; i++){
final Integer index = i;
executorService.execute(()->{
// Simulate N users' concurrent access and download through multiple threads
try {
semaphore.acquire();
count.put(index, index);
semaphore.release();
} catch(Exception e) { e.printStackTrace(); }}); }try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.shutdown();// Disable the scheduling service
System.out.println("Total downloads:"+ count.size()); }}Copy the code
The underlying ConcurrentHashMap splits the original data into small segments with a length of 2 to the power of n, and then locks the segments. Multiple threads process the data at the same time, which improves efficiency while ensuring safety.
extension
atomic
Atomicity means that an operation or operations are either all performed without interruption by any factor, or none at all.
Atomic package
Atomic
Package isJUC
Here’s another one designed specifically for thread safetyJava
Package containing multiple atomic action classesAtomic
Commonly used class
AtomicInteger
AtomicIntergerArray
AtomicBoolean
AtomicLong
AtomicLongArray
In the previous download cases, synchronized keyword was used to ensure the cumulative security of downloads under multiple threads. This can be done in a more lightweight way using Atomic Atomic classes.
Optimize the code
public static AtomicInteger count = new AtomicInteger() ;/ / counter.// The thread is not safe
public static void add(a){
count.getAndIncrement(); //count++
}
Copy the code
CAS algorithm
Pessimistic locking
- Locking is the easiest way to do concurrency, but it’s also the most expensive. An exclusive lock is onePessimistic locking.
synchronized
Is a kind ofAn exclusive lock, which assumes the worst case scenario and is executed only if it ensures that other threads do not interfere, causing all other threads requiring the lock to hang, waiting for the thread holding the lock to release it.
Optimistic locking
- The so-calledOptimistic lockingThat is, each time an operation is performed without locking, it is assumed that there are no conflicts, and if it fails because of conflicts it is retried until it succeeds. Among themCAS(Comparison and exchange,
Compare And Swap
) is a well-known lock-free algorithm.
Atomic application scenarios
While the CAS-based thread safety mechanism is good and efficient, it should be noted that not all thread safety can be implemented in this way. It is only effective for small granularity requirements such as counters, otherwise there would be no locks.