In the accumulator in the previous example 2-6, we added locks to the add method and get method respectively to ensure thread safety. Although the thread safety was ensured, frequent locking and unlocking would cost a lot of performance in the case of fierce competition. In fact, to address this kind of atomicity problem, JDK 1.5 provides a large number of atomic classes, which is a lock-free solution.
Public class CountDemo {private AtomicLong count = new AtomicLong(0); public void add() { count.getAndIncrement(); } public long get() { return count.get(); }}Copy the code
GetAndIncrement () ¶
Example: 5-2 Public Final Long getAndIncrement() {return unsafe. GetAndAddLong (this, valueOffset, 1L); }Copy the code
Enter the Unsafe class:
Public Final Long getAndAddLong(Object var1, Long Var2, Long Var4) {long var6; do { var6 = this.getLongVolatile(var1, var2); } while(! this.compareAndSwapLong(var1, var2, var6, var6 + var4)); return var6; }Copy the code
The Unsafe class is a class that interacts directly with the system, accessing and managing memory resources. Its functions include memory operations, CAS, Class correlation, object operations, thread scheduling, system information retrieval, memory barriers, and array operations.
The CAS instruction takes three arguments: the memory address of the shared variable (A), the comparison value (B), and the new value (C). Only if A and B are equal, will the memory value (A) be updated to C.
Example: 5-4 public final class Unsafe {private static final Unsafe theUnsafe; private Unsafe() {} @CallerSensitive public static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); // The class loader is loaded by the JDK class loader, otherwise the exception if(! VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; }}}Copy the code
The Unsafe class is a singleton implementation that provides the static method getUnsafe to obtain an Unsafe instance. It is legal if and only if the class calling getUnsafe is loaded by the bootstrap classloader. Otherwise, a SecurityException is thrown. The implementation of the atomic classes under the package all relies on Unsafe, and students interested in Unsafe can explore the class on their own.
Summary of atomic brain map
Basic data types
These atomic classes are also relatively simple to use, just remember the usual method:
getAndIncrement() // i++ incrementAndGet() // ++i getAndDecrement() // i-- decrementAndGet() // --i getAndAdd(delta) // Current value +=delta addAndGet(delta)// Current value +=deltaCopy the code
An array of atoms
With AtomicIntegerArray and AtomicLongArray, we can update each element in the array atomically.
Object property update
They update objects’ properties atomically. All three of these methods are implemented using reflection.
Public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {Class<? > caller = Reflection.getCallerClass(); if (AtomicLong.VM_SUPPORTS_LONG_CAS) return new CASUpdater<U>(tclass, fieldName, caller); else return new LockedUpdater<U>(tclass, fieldName, caller); }Copy the code
Object reference
They can be used to implement atomized updates of object references, and I’ll write a Demo with AtomicReference next.
Example: 5-6 public class AtomicReferenceTest { public static void main(String[] args) { AtomicReference<Student> ar = new AtomicReference<Student>(); Student Student = new Student("张三", 20); ar.set(student); Student student1 = new Student(" Student ", 19); ar.compareAndSet(student, student1); System.out.println(ar.get().getName()); System.out.println(ar.get().getAge()); } } class Student { private String name; private int age; public Student(String name, int age){ this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}Copy the code
The above code first creates a Student object, sets the Student object into the AtomicReference object, and then calls the compareAndSet method, which sets the AR through the CAS operation. If ar is student, set it to student1. Running the above code produces the following output:
Li si 19Copy the code