The enhancement of CAs in JAVA8

Source: Internet
Author: User

Note: ifeve.com the same name article for my hair, this article on its basis to make some adjustments. Reprint please specify the source!

I. Enhancement of CAS in JAVA8

A few days ago, I accidentally wrote previously written to Test Atomicinteger and synchronized's self-increasing performance code ran a bit, unexpectedly found Atomicinteger performance than synchronized better, after some reason to find, with the following findings:

In jdk1.7, the getandincrement of Atomicinteger is this:

 Public Final intgetandincrement () { for (;;) {        intCurrent =get (); intNext = current + 1; if(Compareandset (current, next))returnCurrent ; }} Public Final BooleanCompareandset (intExpectintupdate) {    returnUnsafe.compareandswapint ( This, Valueoffset, expect, update);}

And in jdk1.8, this is the case:

 Public Final int getandincrement () {    return unsafe.getandaddint (This, valueoffset, 1);}

It can be seen that in jdk1.8, the Getandaddint method of unsafe is used directly, but in jdk1.7 unsafe, there is no such method. It is essential to conclude that the new approach to unsafe is the key to performance improvement. (The end of the article will include some exploratory processes and inferences)

By looking at the source code of Atomicinteger can be found, affected by the Getandadd, Addandget and other methods.

conclusion: With this increase in CAs, we have another reason to use non-blocking algorithms.

Second, the test method

The test code is given below for reference and testing. It should be noted that this test method is simple and rough, compareandset performance is not as good as synchronized, and can not simply say synchronized is better, the use of the two are different, and in practice, there are business processes, There can be no such high competitive strength, this comparison is only a reference, and the test proves that the performance of atomicinteger.getandincrement has improved significantly.

 Packageperformance;ImportJava.util.concurrent.CountDownLatch;ImportJava.util.concurrent.atomic.AtomicInteger;ImportJava.util.concurrent.locks.LockSupport;/**  * @author[email protected]*/ Public classAtomictest {//test scale, call once getandincreasex to provide a business service to record the time-consuming of providing test_size services    Private Static Final intTest_size = 100000000; //Number of client threads    Private Static Final intThread_count = 10; //use Countdownlatch to let threads start at the same time    PrivateCountdownlatch CDL =NewCountdownlatch (Thread_count + 1); Private intn = 0; PrivateAtomicinteger ai =NewAtomicinteger (0); Private LongStartTime;  Public voidinit () {StartTime=System.nanotime (); }    /*** with atomicinteger.getandincrement, the test result is 1.8:1.7 significant performance improvement *@return     */    Private Final intGetandincreasea () {intresult =ai.getandincrement (); if(Result = =test_size) {System.out.println (System.nanotime ()-startTime); System.exit (0); }        returnresult; }    /*** Using synchronized to complete synchronization, test results of 1.7 and 1.8 almost no performance difference *@return     */    Private Final intGetandincreaseb () {intresult; synchronized( This) {result= n++; }        if(Result = =test_size) {System.out.println (System.nanotime ()-startTime); System.exit (0); }        returnresult; }    /*** Use Atomicinteger.compareandset to do a failure retry at the Java code level (similar to the implementation of the 1.7 atomicinteger.getandincrement), * test results of 1.7 and 1.8 almost no performance difference * @return     */    Private Final intgetandincreasec () {intresult;  Do{result=Ai.get (); }  while(!ai.compareandset (result, result + 1)); if(Result = =test_size) {System.out.println (System.nanotime ()-startTime); System.exit (0); }        returnresult; }     Public classMyTaskImplementsRunnable {@Override Public voidrun () {Cdl.countdown (); Try{cdl.await (); } Catch(interruptedexception e) {e.printstacktrace (); }             while(true) Getandincreasea ();//Getandincreaseb ();        }    }     Public Static voidMain (string[] args)throwsinterruptedexception {atomictest at=Newatomictest ();  for(intn = 0; n < Thread_count; n++)            NewThread (at.NewMyTask ()). Start (); System.out.println ("Start");        At.init ();    At.cdl.countDown (); }}

The following are the test results under the Intel (R) Core (TM) I7-4710HQ CPU @2.50ghz (quad core Eight thread) (less volatile, so each item is tested only four or five times, whichever is the more intermediate value):

jdk1.7atomicinteger.getandincrement 12,653,757,034synchronized 4,146,813,462atomicinteger.compareandset 12,952,821,234jdk1.8atomicinteger.getandincrement 2,159,486,620synchronized 4,067,309,911atomicinteger.compareandset 12,893,188,541  

The exploration and inference of the reason of promotion

At first, I suspect that in 1.8, unsafe uses the native method directly, and 1.7 is the failure retry in Getandincrement, that is, in the Java code level, so the performance difference, so I used jad to decompile the unsafe, get the following code:

 Public Final intGetandaddint (Object obj,LongLinti) {    intJ;  DoJ=getintvolatile (obj, L);  while(!compareandswapint (obj, L, J, J +i)); returnJ;} Public native intGetintvolatile (Object obj,Longl); Public Final native BooleanCompareandswapint (Object obj,LongLintIintj);

and reference the openjdk8 of the unsafe source code:

 Public Final intGetandaddint (Object o,LongOffsetintDelta) {    intv;  Do{v=getintvolatile (o, offset); }  while(!compareandswapint (o, offset, V, v +delta)); returnv;} Public native intGetintvolatile (Object o,Longoffset); Public Final native BooleanCompareandswapint (Object o,LongOffset,intexpected,intx);

As can be seen from the above information, 1.8, the failure retry is also at the Java code level (the difference is transferred to the unsafe Java method inside), is to overturn my guess, so I decided to use reflection, direct access to the unsafe instance, Write the same code as the Unsafe.getandaddint method to test to see if you can find some new clues:

...ImportSun.misc.Unsafe; Public classatomictest {....Privateunsafe unsafe; Private LongValueoffset;  Publicatomictest () {Field F; Try{f= Unsafe.class. Getdeclaredfield ("Theunsafe"); F.setaccessible (true); Unsafe= (Unsafe) f.get (NULL); Valueoffset= Unsafe.objectfieldoffset (Atomicinteger.class. Getdeclaredfield ("value")); }Catch(nosuchfieldexception e) {...} }    Private Final intgetandincreased () {intresult;  Do{result=unsafe.getintvolatile (AI, valueoffset); } while(!unsafe.compareandswapint (AI, valueoffset, result, result+1)); if(Result = =MAX) {System.out.println (System.nanotime ()-startTime); System.exit (0); }        returnresult; }    ...}

But what is disappointing is that this is the same as the getandincrement efficiency of 1.7, clearly the same as the 1.8 Unsafe.getandaddint method, but it is very different efficiency.

Finally, after the ifeve.com of the users of the guidance, the performance of the reasons for the promotion of the following inference, although not to say absolutely correct (because there is no use of the JVM source as an argument), but still have a lot of confidence, thank netizens @ Zhou and @liuxinglanyue!

Unsafe is specially handled and cannot be understood as a regular Java code, except that:

1.8 When calling Getandaddint, if the system support Fetch-and-add, then it executes native method, using Fetch-and-add;

    • If not, follow the Getandaddint method as seen above, in the way of Java code to execute, using the Compare-and-swap;
    • This also coincides with the note above the Unsafe::getandaddint in Openjdk8:
    • // The following contain cas-based Java implementations used on // platforms not supporting native instructions

RELATED links:
Http://ashkrit.blogspot.com/2014/02/atomicinteger-java-7-vs-java-8.html
Http://hg.openjdk.java.net/jdk8u/hs-dev/jdk/file/a006fa0a9e8f/src/share/classes/sun/misc/Unsafe.java

The enhancement of CAs in JAVA8

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.