Reprinted from: http://www.blogjava.net/xylz/archive/2010/07/04/325206.html
Before JDK 5, the Java language relied on the synchronized keyword to ensure synchronization, which would lead to a lock (the lock will be discussed later ).
The lock mechanism has the following problems:
(1) In the multi-thread competition, locking and Releasing locks will lead to many context switches and scheduling delays, resulting in performance problems.
(2) A thread holding a lock will cause all other threads needing this lock to suspend.
(3) If a thread with a higher priority waits for a lower-priority thread to release the lock, the priority will be reversed, causing performance risks.
Volatile is a good mechanism, but volatile cannot guarantee atomicity. Therefore, the synchronization will eventually return to the lock mechanism.
An exclusive lock is a pessimistic lock. Synchronized is an exclusive lock that will cause all other threads to be locked to suspend and wait for the thread holding the lock to release the lock. Another more effective lock is the optimistic lock. The so-called optimistic lock means that an operation is completed without locking each time. If a conflict fails, the operation is retried until the operation is successful.
CAS operation
The above optimistic locks use cas, compare and swap.
CAS has three operands, memory value V, old Expected Value A, and new value B to be modified. If and only when the expected value a is the same as the memory value V, change the memory value V to B. Otherwise, nothing is done.
Nonblocking Algorithms)
Failure or suspension of a thread should not affect the failure or suspension algorithm of other threads.
The modern CPU provides special commands to automatically update shared data and detect interference from other threads. compareandset () replaces the lock.
Come up with atomicinteger to study how data is correct without a lock.
Private volatile int value;
First, I have no idea that the volatile primitive may need to be used in the absence of a lock mechanism to ensure that data between threads is visible (shared ).
In this way, you can directly read the value of the variable.
Public final int get (){
Return value;
}
Then let's see how ++ I does it.
Public final int incrementandget (){
For (;;){
Int current = get ();
Int next = Current + 1;
If (compareandset (current, next ))
Return next;
}
}
Here the CAS operation is used. Each time the data is read from the memory, the CAS operation is performed on the data and the result after the plus 1 is executed. If the result is successful, the result is returned. Otherwise, retry until the operation is successful.
Compareandset uses JNI to perform CPU instruction operations.
Public final Boolean compareandset (INT exact CT, int update ){
Return unsafe. compareandswapint (this, valueoffset, exact CT, update );
}
The overall process is like this. The CAS command of the CPU and JNI are used to complete the Java non-blocking algorithm. Other atomic operations are completed using similar features.
The entire J. u. C is built on cas. Therefore, for the synchronized Blocking Algorithm, J. U. C has greatly improved its performance. This document describes how to use CAs to construct non-blocking counters, queues, and other data structures.
CAS looks great, but it may cause "ABA problems ".
The CAS algorithm needs to retrieve data at a certain time point in the memory before it is implemented, and compare and replace the data at the next time. This time difference class will lead to data changes.
For example, if one thread extracts a from the memory location V, two also extracts a from the memory, and two performs some operations to change it to B, then two changes the data at the V position to A. At this time, the CAS operation on thread one finds that the memory is still a, and then the one operation is successful. Although the CAS operation on thread one is successful, it does not mean that this process is correct. If the source value is restored after the chain table header changes twice, it does not mean that the chain table does not change. Therefore, the atomic operation atomicstampedreference/atomicmarkablereference mentioned above is very useful. This allows atomic operations on a changing element.
References:
(1) Introduction to non-Blocking Algorithms
(2) Popular Atoms