There are many atomic classes AtomicInteger.java under the JDK concurrent package, which provide atomic update operations.
The following is a cas demo method
public static void casDemo(){ AtomicInteger atomicInteger = new AtomicInteger(1); int x = atomicInteger.getAndIncrement(); System.out.println("x = " + x); }
Here getAndIncrement will give 1 by itself and is thread-safe.
Follow up JDK source code
AtomicInteger.getAndIncrement() method
/** * Atomically increments the current value, * with memory effects as specified by {@link VarHandle#getAndAdd}. * * <p>Equivalent to {@code getAndAdd(1)}. * * @return the previous value */ public final int getAndIncrement() { return U.getAndAddInt(this, VALUE, 1); }
The annotation shows that the function of the method is to atomically update the variable, and continue to follow the U.getAndAddInt() method
/** * Atomically adds the given value to the current value of a field * or array element within the given object {@code o} * at the given {@code offset}. * * @param o object/array to update the field/element in * @param offset field/element offset * @param delta the value to add * @return the previous value * @since 1.8 */ @HotSpotIntrinsicCandidate public final int getAndAddInt (Object o, long offset, int delta) { int v; to { v = getIntVolatile (o, offset); } while (!weakCompareAndSetInt(o, offset, v, v + delta)); return v; }
The JDK 10 I use here may be a little different, continue to follow the weakCompareAndSetnt() method
@HotSpotIntrinsicCandidate public final boolean weakCompareAndSetInt(Object o, long offset, int expected, int x) { return compareAndSetInt(o, offset, expected, x); }
Continue to follow up the compareAndSetInt() method
/** * Atomically updates Java variable to {@code x} if it is currently * holding {@code expected}. * * <p>This operation has memory semantics of a {@code volatile} read * and write. Corresponds to C11 atomic_compare_exchange_strong. * * @return {@code true} if successful */ @HotSpotIntrinsicCandidate public final native boolean compareAndSetInt(Object o, long offset, int expected, int x);
Here is a native method, a native method, that is, a native method, that calls methods implemented in other languages. It can be seen from openjdk that jvm is mainly implemented by C++. I saw others posted the openjdk source code on the Internet.
// Adding a lock prefix to an instruction on MP machine // VC++ doesn't like the lock prefix to be on a single line // so we can't insert a label after the lock prefix. // By emitting a lock prefix, we can define a label after it. #define LOCK_IF_MP(mp) __asm cmp mp, 0 \ __asm is L0 \ __asm _emit 0xF0 \ __asm L0: inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) { // alternative for InterlockedCompareExchange int mp = os::is_MP(); __asm { mov edx, dest mov ecx, exchange_value mov eax, compare_value LOCK_IF_MP(mp) cmpxchg dword ptr [edx], ecx } }
In this source code, you can see that the compiled cmpxchg instruction is used. In the case of multiple CPUs, the lock prefix will be added before the instruction to ensure the atomicity of instruction execution. Single-core CPUs will not be prefixed with lock.
How to ensure the atomicity of this instruction is a matter of the CPU. There is information on the Internet that it locks the bus, locks the shared memory, etc.
cas advantages:
1. No thread blocking, no thread context switching
shortcoming:
1. Thread spin, cpu idling
2. The atomicity of multiple variables is not guaranteed
3. Can't perceive the ABA problem, you can consider using the version number to solve it
refer to
1. http://zl198751.iteye.com/blog/1848575
2. https://blog.csdn.net/xiuye2015/article/details/53406432