ABA problems caused by CAS (Compare and Swap)
Problem description
In multi-threaded situations, each thread uses CAS operations to modify data A to B, but we only want one thread to modify the data correctly and modify it only once. When concurrency, one of the threads has changed a successfully to B, but the thread concurrent scheduling process has not yet been dispatched, during this period, another thread (not in the concurrent request thread) B is modified to a, then the original thread in the concurrency can be a CAS operation to change a to B
Test Case:
Public classAbapro {Private Static FinalRandom random =NewRandom (); Private Static FinalString B = "B"; Private Static FinalString a = "a"; Public Static FinalAtomicreference<string> atomic_reference =NewAtomicreference<>(A); Public Static voidMain (string[] args)throwsinterruptedexception {FinalCountdownlatch Startlatch =NewCountdownlatch (1); thread[] Threads=NewThread[20]; for(inti=0; I < 20; i++) {Threads[i]=NewThread () {@Override Public voidrun () {String OldValue=Atomic_reference.get (); Try{startlatch.await (); } Catch(interruptedexception e) {e.printstacktrace (); } Try{thread.sleep (Random.nextint ()&500); } Catch(interruptedexception e) {e.printstacktrace (); } if(Atomic_reference.compareandset (OldValue, B)) {System.out.println (Thread.CurrentThread (). Getn Ame ()+ "The original value has been modified, this value is:" +atomic_reference.get ()); } } }; Threads[i].start (); } startlatch.countdown (); Thread.Sleep (200); NewThread () {@Override Public voidrun () {Try{thread.sleep (Random.nextint ()& 200); } Catch(interruptedexception e) {e.printstacktrace (); } String oldval=Atomic_reference.get (); while(!Atomic_reference.compareandset (Atomic_reference.get (), A)); System.out.println (Thread.CurrentThread (). GetName ()+ "The value" +oldval+ "has been modified to the original value: A"); }}.start (); }}
Results:
Thread-12 已经对原始值进行了修改,此时值为: BThread-20 已经将值 B 修改成原始值: AThread-14 已经对原始值进行了修改,此时值为: B
You can see that the threads in the concurrency Thread-12 have successfully modified A to B, the other threads Thread-20 Change B to a at some point, and the threads in the concurrency Thread-14 can successfully change A to B again, although the end result is B, but halfway through the process of being modified, in some cases it is caused
Solution Solutions
Java AtomicStampedReference is provided to solve this problem, it is based on a version or a state, in the process of modifying not only the ratio, but also compare the version number
Public classAabproresolve {Private Static FinalRandom random =NewRandom (); Private Static FinalString B = "B"; Private Static FinalString a = "a"; Private Static FinalAtomicstampedreference<string> atomic_stamped_reference =NewAtomicstampedreference<> (a,0); Public Static voidMain (string[] args)throwsinterruptedexception {FinalCountdownlatch Startlatch =NewCountdownlatch (1); thread[] Threads=NewThread[20]; for(inti=0; I < 20; i++) {Threads[i]=NewThread () {@Override Public voidrun () {String OldValue=atomic_stamped_reference.getreference (); intStamp =Atomic_stamped_reference.getstamp (); Try{startlatch.await (); } Catch(interruptedexception e) {e.printstacktrace (); } Try{thread.sleep (Random.nextint ()& 500); } Catch(interruptedexception e) {e.printstacktrace (); } if(Atomic_stamped_reference.compareandset (OldValue, B, Stamp, stamp+1) {System.out.println (Thread.CurrentThread (). GetName ()+ "The original value:" +oldvalue+ "has been modified, the value is:" +atomic_stamped_reference.getreference ()); } } }; Threads[i].start (); } thread.sleep (200); Startlatch.countdown (); NewThread () {@Override Public voidrun () {Try{thread.sleep (Random.nextint ()& 200); } Catch(interruptedexception e) {e.printstacktrace (); } intStamp =Atomic_stamped_reference.getstamp (); String Oldval=atomic_stamped_reference.getreference (); while(!Atomic_stamped_reference.compareandset (B, A,stamp, Stamp+1) ) {Stamp=Atomic_stamped_reference.getstamp (); } System.out.println (Thread.CurrentThread (). GetName ()+ "The value" +oldval+ "has been modified to the original value: A"); }}.start (); }}
Results:
Thread-1 已经对原始值: A 进行了修改,此时值为: BThread-20 已经将值 B 修改成原始值: A
You can see that threads in a concurrent period only Thread-1 modify a to ensure that only one thread modifies the data, and that other threads after a short period of concurrency Thread-20 have no effect on their modifications.
Optimization scheme, you can refer to:
78797203
Java concurrent programming principle and Combat 43: ABA Problem----CAS