AtomicStampReference

Solve ABA problem in CAS

What is the ABA

ABA problem: During CAS operations, A thread changes the value of A variable from A to B, but changes it back to A. Other threads find that A has not changed, so CAS will swap the value. In fact, the value has been changed, which is inconsistent with the core idea of CAS

ABA Solution

Each time a variable is updated, the version number of the variable is updated. If a variable has been modified by a thread, the version number must be incrementally updated, thus solving the ABA problem

AtomicReference demonstrates ABA problems

package com.keytech.task; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; public class AtomicIntegerTest { private static AtomicReference<Integer> count=new AtomicReference<>(10); public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(()->{ boolean b = count.compareAndSet(10, 12); If (b){system.out.println (thread.currentThread ().getName()+" count="+count.get()); } boolean c =count.compareAndSet(12, 10); If (c){system.out.println (thread.currentThread ().getName()+" count="+count.get()); }}); executorService.execute(()->{ boolean b = count.compareAndSet(10, 100); If (b){system.out.println (thread.currentThread ().getName()+" count="+count.get()); }}); executorService.shutdown(); }} // Pool-1-thread-1 is modified successfully count=12 //pool-1-thread-1 is modified successfully count=10 //pool-1-thread-2 is modified successfully count=100Copy the code

Pool-1-thread-1 change count from 10 to 12, and change count from 12 to 10. Pool-1-thread-2 successfully changed count from 10 to 100. ABA problems arise.

AtomicStampedReferenceTo solveABAThe problem of

Take the implementation of a counter, which is usually used to count the number of people who are online. Online +1 and offline -1 are typical ABA scenarios.

package com.keytech.task; import java.util.concurrent.atomic.AtomicStampedReference; Public class CounterTest {private AtomicStampedReference<Integer> count=new AtomicStampedReference<Integer>(0,0); public int getCount(){ return count.getReference(); } public int increment(){ int[] stamp=new int[1]; while (true){ Integer value = count.get(stamp); int newValue=value+1; boolean b = count.compareAndSet(value, newValue, stamp[0], stamp[0] + 1); if(b){ return newValue; } } } public int decrement(){ int[] stamp=new int[1]; while(true){ Integer value=count.get(stamp); int newValue=value-1; boolean b = count.compareAndSet(value, newValue, stamp[0], stamp[0] + 1); if(b){ return newValue; }}}}Copy the code

Call counter

package com.keytech.task; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; public class AtomicIntegerTest { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); Semaphore semaphore=new Semaphore(200); CounterTest counterTest=new CounterTest(); for (int i = 0; i < 5000; i++) { executorService.execute(()->{ try{ semaphore.acquire(); counterTest.increment(); semaphore.release(); }catch (Exception e){ e.printStackTrace(); }}); executorService.execute(()->{ try{ semaphore.acquire(); counterTest.decrement(); semaphore.release(); }catch (Exception e){ e.printStackTrace(); }}); } executorService.shutdown(); System.out.println(counterTest.getCount()); }} // Prints 0Copy the code

AtomicBooleanEnsure that high concurrency is executed only once

package com.keytech.task; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; public class AtomicBooleanTest { private static AtomicBoolean isHappen=new AtomicBoolean(false); public static int clientTotal=5000; public static int threadTotal=200; public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); Semaphore semaphore=new Semaphore(threadTotal); for (int i = 0; i < clientTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); }catch (Exception e){ e.printStackTrace(); }}); } executorService.shutdown(); } private static void update(){if(isHappen.compareAndSet(false, true)){system.out.println (" happen.com "); }}} // Execute only onceCopy the code