The principle and analysis of the atomic package of Java Beauty [from rookie to expert walkthrough]

Source: Internet
Author: User
Tags cas

Two cyan

Personal site: zhangerqing.cn email: [Email protected] Weibo: HTTP://WEIBO.COM/XTFGGEF


Atomic Introduction

The atomic package is another Java package specifically designed for thread safety under Java.util.concurrent and contains multiple atomic manipulation classes. This package provides a set of atomic variable classes. The basic feature is that in a multithreaded environment, when there are multiple threads executing the methods contained by instances of these classes at the same time, there is exclusivity, that is, when a thread enters the method and executes the instruction, it is not interrupted by another thread, and the other thread is like a spin lock until the method executes. It is only a logical understanding that the JVM chooses a second thread from the waiting queue to enter. It is actually implemented with hardware-related instructions that do not block threads (or simply block at the hardware level). You can manipulate basic data, basic data in an array, and basic data in a class. The atomic variable class is equivalent to a generalized volatile variable that supports both atomic and conditional read-write operations. --from the blog @chenzehe .


problems with traditional locks

Let's take a look at an example: Counter (Counter), using the more convenient lock mechanism in Java synchronized keyword, the initial code is as follows:


In fact, like this lock mechanism, to meet the basic requirements is no problem, but sometimes our needs are not so simple, we need more efficient, more flexible mechanism, synchronized keyword is based on blocking locking mechanism, that is, when a thread has a lock, Other threads that access the same resource need to wait until the thread releases the lock, and there are some problems: first, what if the blocked thread has a high priority? Second, what if the thread that gets the lock does not release the lock? (This is a very bad situation). In another case, if there are a large number of threads to compete for resources, then the CPU will spend a lot of time and resources to deal with these competitions (in fact, the main work of the CPU is not these), and there may be some, such as deadlocks, and finally, the lock mechanism is a relatively coarse, large granularity mechanism, This is a bit too cumbersome for a demand like a counter, so we expect a more appropriate, more efficient thread-safety mechanism for this requirement.


Hardware synchronization Policy

Processors now support multiprocessing and, of course, multiple processors share peripherals and memory, while the instruction set is enhanced to support some of the special needs of multiprocessing. In particular, almost all processors can block other processors to update shared variables.


Compare and swaps (CAS)

The current processor basically supports CAS, but each factory implements the algorithm is not the same, each CAS operation process contains three operators: a memory address V, an expected value A and a new value B, when the operation if the value of this address is equal to the expected value A, The value on the address is assigned to the new value B, otherwise no action is made. The basic idea of CAS is that if the value on this address is equal to the expected value, it is given a new value, otherwise nothing is done, but the original value is returned. Let's look at an example that explains the CAS implementation process (not the real CAS implementation):

Class Simulatedcas {private int value;public synchronized int getValue () {return value;} public synchronized int Compareandswap (int expectedvalue, int newvalue) {int oldValue = value;if (value = = Expectedvalue) v Alue = Newvalue;return OldValue;}}

The following is a counter implemented with CAs

public class Cascounter {    private simulatedcas value;    public int GetValue () {        return value.getvalue ();    }    public int increment () {        int oldValue = Value.getvalue ();        while (Value.compareandswap (OldValue, OldValue + 1)! = oldValue)            oldValue = Value.getvalue ();        return oldValue + 1;    }}

Atomic class before JDK5.0, it is not possible to implement a lock-free, no-wait algorithm unless a local library is used, which is possible since the atomic variable class. The following diagram is the class structure under the Java.util.concurrent.atomic package.

    • Scalar class: Atomicboolean,atomicinteger,atomiclong,atomicreference
    • Array class: Atomicintegerarray,atomiclongarray,atomicreferencearray
    • Updater class: Atomiclongfieldupdater,atomicintegerfieldupdater,atomicreferencefieldupdater
    • Compound Variable class: Atomicmarkablereference,atomicstampedreference

The first group of atomicboolean,atomicinteger,atomiclong,atomicreference these four basic types is used to deal with Boolean, Integer, Long Integer, object four kinds of data, its internal implementation is not simple to use synchronized, It is a more efficient way of CAS (compare and swap) + volatile and native methods, which avoids the high overhead of synchronized and greatly improves execution efficiency. Let's look at an example of the atomic operation that corresponds to our usual i++: Getandincrement ()

public static void Main (string[] args) {Atomicinteger ai = new Atomicinteger (); SYSTEM.OUT.PRINTLN (AI); ai.getandincrement (); SYSTEM.OUT.PRINTLN (AI);}

We can look at the implementation of Atomicinteger:

    /** * atomically increments by one of the current     value.     *     * @return The previous value */public    final int getandincrement () {        return unsafe.getandaddint (this, Valueoffset, 1);    }

Here directly call a class called unsafe to deal with, it seems we need to continue to look at the source of unsafe class. JDK8 Sun.misc under Unsafe class, click to view the source code

From the source note, this class is a collection of methods for performing low-level, unsafe operations. Although this class and all methods are public, the use of this class is still limited, and you cannot use the class directly in your own Java program, because only the code of the message can obtain an instance of the class. So our usual code is unable to use this class, because its design operation is too partial, if the operation inadvertently may bring a great disaster, so directly prohibit the access of ordinary code, of course, JDK use is no problem.


CAs in atomic

From the previous explanation, the principle of CAS is to compare the expected value with the original value, if the same is updated to a new value, here This "original value" how to, we look at the implementation of Atomicinteger:

Setup to use Unsafe.compareandswapint for updates    private static final unsafe unsafe = Unsafe.getunsafe ();    Private static final long valueoffset;    static {        try {            valueoffset = Unsafe.objectfieldoffset                (AtomicInteger.class.getDeclaredField ("value"));        } catch (Exception ex) {throw new Error (ex);}    }

Here's a way to use the unsafe method Objectfieldoffset (), view the source code:

/** * The location of a given static field, in conjunction with {@link * #staticFieldBase}.     * <p>do not expect to perform any sort of arithmetic on this offset;     * It is just a cookie which are passed to the unsafe heap memory accessors.  * * <p>any given field always has the same offset, and no distinct * fields of the same class would     Ever has the same offset. * * <p>as of 1.4.1, offsets for fields is represented as long values, * Although the Sun JVM does not use T     He most significant. * It's hard-to-imagine a JVM technology which needs more than * a few bits to encode an offset within a non-array obj ECT, * However, for consistency and other methods in this class, * This method reports its result as a Long value     . * @see #getInt (Object, long) */public native long Objectfieldoffset (Field f);

This method is used to get the memory address of the "original value" we mentioned earlier. is a local method and the return value is Valueoffset. Its parameter field is the value attribute defined in Atomicinteger:

    private volatile int value;    /**     * Creates a new atomicinteger with the given initial value.     *     * @param initialvalue The initial value     *    /public atomicinteger (int initialvalue) {        value = InitialValue;    }    /**     * Creates a new Atomicinteger with initial value {@code 0}.     *    /Public Atomicinteger () {    }

Value is a volatile variable that is visible in memory and is not allowed to be copied by any thread, so the JVM can guarantee that any thread will always get the latest value for that variable at any moment. The value here can be passed in when the Atomicinteger class is initialized, or it can be left blank and automatically assigned a value of 0.


Let's go back to CAS and see how the Getandincrement () method is implemented using CAs.

/** * atomically increments by one of the current     value.     *     * @return The previous value */public    final int getandincrement () {        return unsafe.getandaddint (this, Valueoffset, 1);    }

Go on:

Public final int getandaddint (Object o, long offset, int delta) {        int v;        do {            v = getintvolatile (o, offset),//------------0---------------        } while (!compareandswapint (o, offset, V, v + Delta));//-------------1-------------        return v;    }

  /**     * atomically update Java variable to <tt>x</tt> if it is currently     * Holding <TT>EXPECTED< ;/tt>.     * @return <tt>true</tt> If successful     *    /public Final native Boolean compareandswapint (Object o, Long offset,//---------------2--------------                                                  int expected,                                                  int x);

I explain a little bit, in fact, the compareandswapint annotation is very clear, the atomic value of the variable is updated to X, if successful returns true, we know that if we create the Atomicinteger instance without passing arguments, the original variable value is 0, so the above The value of v obtained at----------0-----------is 0 and the code at 1 is:

while (!compareandswapint (o, offset, 0, 1)) We know that the value of the address offset points to is the original variable initial values of 0, so as the expected value of 0 is the same, so the initial value is assigned to 1, return true, take the inverse to false, The loop ends with a value of 0 before the update is returned. This is similar to the i++ operation of the implementation of atomic operations, of course, eventually the implementation of the CAs are native, in C language, we do not see the source, there is time I will decompile this code to see.


CAS Thread safety

For a long while, we are going back to the original question: how can we achieve thread safety? Please consider this problem yourself first, in fact, we do not do any synchronous operation in the language level, we can see the source code does not have any lock added on it, but why is it thread-safe? This is the mystery of these classes under the atomic package: The language level does not do the processing, we put it to hardware-cpu and memory, using the CPU's multi-processing capabilities, hardware-level blocking, coupled with the characteristics of volatile variables can be implemented based on atomic operation of thread safety. So, CAS is not non-blocking, but blocking is not in terms of language, threading, but on the hardware level, so no doubt such operations will be faster and more efficient!


Summarize

Although the CAS-based thread safety mechanism is very good and efficient, but to say that not all thread safety can be implemented in such a way, this is only suitable for some small granularity, such as counters such as the need to use it to be effective, otherwise there will be no lock exists.


Have questions please feel free to contact me, I will promptly reply, Welcome to discuss together!

Two green personal site: zhangerqing.cn e-mail: [email protected] Weibo: HTTP://WEIBO.COM/XTFGGEF

The principle and analysis of the atomic package of Java Beauty [from rookie to expert walkthrough]

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.