DEV Community

ChelseaLiu0822
ChelseaLiu0822

Posted on

Lock-free concurrency-optimistic locking (non-blocking)

CAS and volatile
CAS: compare And Set (compare And Swap), must be an atomic operation

Image description

The bottom layer of CAS is the lock cmpxchg instruction (X86 architecture), which ensures operation under both single-core CPU and multi-core CPU.
atomicity
CAS operations require volatile support to ensure that the latest results of shared variables are obtained to achieve [compare and exchange]Effect.

High lock-free efficiency

In a lock-free situation, even if the retry fails, the thread is always running at high speed without stopping, and synchronized will make
When the thread does not acquire the lock, a context switch occurs and it enters blocking.
In the lock-free case, because the thread needs to keep running, additional CPU support is required. If the thread is not allocated time,
file, it will still enter the runnable state, and it will still cause context switching.

CAS features

CAS is based on the idea of optimistic locking: it is not afraid of other threads modifying shared variables.
synchronized is based on the idea of pessimistic locking: preventing other threads from modifying shared variables
CAS embodies lock-free concurrency and non-blocking concurrency:
Synchronized is not used, so the thread will not be blocked.
However, if competition is fierce and retries occur frequently, efficiency will be affected.

Atomic integer

AtomicBoolean, AtomicInteger, AtomicLong basic types of atoms
Construction method:
AtomicInteger i = new AtomicInteger(value) value is modified by volatile
Auto-increment method:
i.incrementAndGet()i++
i.getAndIncrement()++i
Similar to autodecrement
Get value:
i.get()
addition:
i.getAndAdd(value) i.addAndGet(value)
multiplication:
i.updateAndGet (IntUnaryOperator operation) (IntUnaryOperator is a function interface)
i.getAndUpdate
e.g i.updateAndGet(x -> x*10)
principle:

Image description

Atomic citation

AtomicReference, AtomicMarkableReference, AtomicStampedReference
AtomicReference determines the protected object through generics
Basically the same usage as AtomicInteger

ABA question:

The initial variable is A. Before CAS, other threads changed the shared variable to B, and another thread changed B to
A. CAS cannot sense whether the shared variable has been modified. CAS can only determine whether the shared variable is the same as the original value.

AtomicStampedReference

By adding the version number attribute to the shared variable, we can determine whether the shared variable has been modified. If the CAS has been modified,
will fail
Construction method:
AtomicStampedReference ref = new AtomicStampedReference<>("A",0(version
This number))
There is no get() method, only getReference() method
compareAndSet(prev, new, stamp, newStamp), you need to pass in the original version number, and
Modified new version number

AtomicMarkableReference

Only care whether the shared variable has been changed, not how many times it has been changed, just add boolean to judge
Construction method:
AtomicMarkableReference ref = new AtomicMarkableReference<> (value,
true)
compareAndSet(prev, new, expectedMark, newMark) needs to pass in the original mark and modify next new tag

Atomic array

AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray
Protect the thread safety of elements within an array
Usage is basically the same as AtomicInteger
The length() method returns the array length
getAndIncrement(index) auto-increments the elements in the array

Atomic field updater

Protect object member variables from thread safety
AtomicReferenceFieldUpdater, AtomicIntegerFieldUpdater,
AtomicLongFieldUpdater
Construction method:
AtomicReferenceFieldUpdater updater = new AtomicReferenceFieldUpdater(protect
Object.class, reference object.class, member variable)
compareAndSet(object, initial value, expected value)
The member properties of the object must be modified with volatile

Atomic Accumulator

More efficient than the self-increment method in AtomicLong
LongAdder
increment() self-increment method
reason:
When multiple threads compete, CAS competition becomes fierce, resulting in low efficiency. When there is competition, LongAdder sets multiple accumulation units, and different threads accumulate different units (Cell variables), which reduces CAS retry failures, thereby improving performance. efficiency

Unsafe object

Provides very low-level methods for operating memory and threads. Unsafe objects cannot be called directly and can only be obtained through reflection.
It is the underlying implementation of the atomic class

Unsafe CAS operation

Get the offset address of the domain
long offset = unsafe.objectFieldOfSet(xxx.class.getDeclareField(variable name))
Perform CAS operations
unsafe.compareAndSwapInt (modify object, field offset, current value, expected value)
compareAndSwapObject has different methods for different types of data

Top comments (0)