Java-based concurrent operation of atoms Summary

When the program updates a variable, and if multiple threads simultaneously update this variable, the result may be obtained with different expectations. For example: There is a variable i, a thread of execution A i + 1, thread B is also performed i + 1, after the operation of the two threads, the value of the variable i is 3 may not be desirable, but 2. This is because the value of i can get it at the time of thread A and B are 1 thread of execution, which is thread-safe update operations, we typically use synchronized to solve this problem, will not be synchronized to ensure that multi-threaded At the same time update the variable i.

Java1.5 from the start, provided JDK java.util.concurrent.atomic package, this package type atomic operation, there is provided the use of a simple, efficient performance, security thread updates a variable manner.

atomic package which provided a total of 13 classes, classified into four types, namely: atomic update the basic type , atomic update array , atomic update references , atomic update attributes , which are 13 classes using Unsafe package classes.

First, the basic types of atomic update

atomic provides three basic types of classes for atomic update: Update shaping are AtomicInteger atom, AtomicLong atomic update long integer, AtomicBoolean bool value updated atoms. Since this method provides the three classes is almost the same, therefore this section AtomicInteger example.

  AtomicInteger common methods are:

    1.int addAndGet (int delta): Example values ​​atomically the inputted values ​​are added, and the results returned

    2.boolean compareAndSet (int expect, int update): If the input value is equal to the expected value, atomically set the value of the input value

    3.final int getAndIncrement (): atomically current value plus 1 and returns the value before the addition

    4.void lazySet (int newValue): eventually set newValue, after use lazySet settings may cause other threads within a short time after can still read the old value.

    5.int getAndSet (int newValue): atomically set the current value to newValue, and returns the old value before setting

  How getAndIncremen atomic operation is to achieve it? Let's look at getAndIncremen implementation code, and implement the principles of analysis. getAndIncremen the codes are as follows:  

public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

  We can see getAndIncrement called unsafe in getAndAddInt, achieve getAndAddInt of:

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

  getAndAddInt Unsafe called the native method: getIntVolatile and compareAndSwapInt, first obtain the current value of the do-while loop, then through CAS to determine whether the current value and the current agreement, if the agreement means that the value is not modified by another thread, the current value is set the current value of + var4 ,, if not equal the program proceeds letter CAS cycle.

Because atomic provide only atomic type int, long, and boolean, then the other basic types, such as byte, char, float, double atomic how to operate it, atomic operations are through Unsafe achieve, let's look at the Unsafe achieve

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

  Unsafe CAS only provides three methods: compareAndSwapObject , compareAndSwapInt and compateAndSwapLong , other types are converted into three types corresponding method to re-use atomic updates.

AtomicBoolean introduction and use

Use AtomicInteger class

 

Second, atomic update array

  Providing three classes in atomic elements for atomic updates inside the array, namely:

  AtomicIntegerArray: atomic update shaping array of elements

  AtomicLongArray: atomic update long integer array of elements

  AtomicReferenceArray: atomic update the reference array elements

  Because the method provided by each class which are consistent AtomicIntegerArray therefore be described as an example. AtomicIntegerArray mainly provide atomically update integer array, a common method is as follows:

  int addAndGet (int i, int delta): atomically input values ​​to the sum of the index array element i

  boolean compareAndSet (int i, int expect, int update): If the current value is equal to the expected value, the elements of the array Atomically i is set to update the position values.

  Examples are as follows:

public class AtomicIntegerArrayTest {

    private static int[] value = new int[]{1,2,3};
    private static AtomicIntegerArray atomicInteger = new AtomicIntegerArray(value);

    public static void main(String[] args){
        atomicInteger.getAndSet(0,12);
        System.out.println(atomicInteger.get(0));
        System.out.println(value[0]);
    }

}

  Note that, by constructing an array of value passed into the method, then AtomicIntegerArray will present a copy of the array, so when AtomicIntegerArray array element internal modifications will not affect the incoming array.

Third, update the reference type atom

  The basic types of atomic updates AtomicInteger can only update a variable, if you want to update multiple atomic variables, you need to use atomic updates provided by the class reference type. Atomic atomic reference type package provides several major categories:

  AtomicReference: atomic update reference type

  AtomicReferenceFieldUpdater: atomic update reference types in the field

  AtomicMarkableReference: update the reference type atom marked position. Atom may update a boolean flag and reference types. Constructor is AtomicMarkableReference (V initialRef, booleaninitialMark)

  Above class method provides basically the same, our AtomicReference an example:

public class AtomicReferenceTest {

    private static AtomicReference<User> reference = new AtomicReference<User>();

    public static void main(String[] args){
        User user = new User("tom",23);
        reference.set(user);
        User updateUser = new User("ketty",34);
        reference.compareAndSet(user,updateUser);
        System.out.println(reference.get().getName());
        System.out.println(reference.get().getAge());
    }


    static class User{

        private String name;
        private int age;

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }
}

The above code first creates a user object, then the object is set into AtomicReference user, the last update made by atoms of compareAndSet, results are as follows:

ketty 
34

Fourth, atomic update field class

If you need to update an atomic object is a field, it is necessary to use atomic updates attributes related classes, atomic provides several classes for atomic updates about the property:

  AtomicIntegerFieldUpdater: atomic update shaping properties updater

  AtomicLongFieldUpdater: atomic updates long integer updater

  AtomicStampedReference: atomic update version number with a reference type. Such references are associated with the integer value it can be used to update data and the version number of atoms, can solve the problems that may occur when ABA using CAS atomic updates.

  Want atoms update fields, requires two steps:

  1. Because atomic update field class is an abstract class, you must be used every time you use the static method newUpdater () to create an updater, and the need to set up classes and attributes you want to update

  2. Update class fields (attributes) must use public volatile modifier

  This section only AstomicIntegerFieldUpdater example to explain, AstomicIntegerFieldUpdater sample code is as follows:

public class AtomicIntegerFieldUpdaterTest {

    //创建原子更新器
    private static AtomicIntegerFieldUpdater<User> updater = AtomicIntegerFieldUpdater.newUpdater(User.class,"age");

    public static void main(String[] args){
        User user = new User("ketty",21);
        //ketty长了一岁
        updater.getAndIncrement(user);
        System.out.println(updater.get(user));
    }

    static class User{

        private String name;
        public volatile int age;

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }
}

  If the age of modification symbols are not public volatile, it returns an error:

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: java.lang.IllegalAccessException: Class com.ysl.atomic.AtomicIntegerFieldUpdaterTest can not access a member of class com.ysl.atomic.AtomicIntegerFieldUpdaterTest$User with modifiers "private"
    at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.<init>(AtomicIntegerFieldUpdater.java:405)
    at java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdater.java:88)
    at com.ysl.atomic.AtomicIntegerFieldUpdaterTest.<clinit>(AtomicIntegerFieldUpdaterTest.java:8)
Caused by: java.lang.IllegalAccessException: Class com.ysl.atomic.AtomicIntegerFieldUpdaterTest can not access a member of class com.ysl.atomic.AtomicIntegerFieldUpdaterTest$User with modifiers "private"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    at sun.reflect.misc.ReflectUtil.ensureMemberAccess(ReflectUtil.java:103)
    at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.<init>(AtomicIntegerFieldUpdater.java:394)
    ... 2 more

 

Guess you like

Origin www.cnblogs.com/shamo89/p/10319385.html