A few days ago, I accidentally ran the code I wrote previously to test the auto-increment performance of AtomicInteger and synchronized. I unexpectedly found that the performance of AtomicInteger is better than synchronized. After searching for the reasons, I found The following is found:
In jdk1.7, the getAndIncrement of AtomicInteger is like this:
public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } } public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
And in jdk1.8, it is like this:
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 Unsafe of jdk1.7, there is no such method. (PS: In order to find out the reason, I decompiled Unsafe and found that the failed retry of CAS was done in the getAndAddInt method. I used reflection to get the Unsafe instance and wrote the same code as getAndAddInt, but the test results were the same as jdk1 .7's getAndIncrement is just as slow. I don't know what kind of black magic is played in Unsafe. Please give me some advice.) (Supplement: There is an inference at the end of the article)
You can find out by looking at the source code of AtomicInteger that the affected There are also most methods such as getAndAdd and addAndGet.
With this enhancement to CAS, we have another reason to use non-blocking algorithms.
Finally, the test code is given. It should be noted that this test method is simple and crude. The performance of compareAndSet is not as good as synchronized. It cannot simply be said that synchronized is better. There are differences in how they are used. Moreover, in actual use, there is also business processing, and it is impossible to have such a high competition intensity. This comparison is only used as a reference. What this test can prove is that the performance of AtomicInteger.getAndIncrement has been greatly improved.
package performance; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.LockSupport; public class AtomicTest { //测试规模,调用一次getAndIncreaseX视作提供一次业务服务,记录提供TEST_SIZE次服务的耗时 private static final int TEST_SIZE = 100000000; //客户线程数 private static final int THREAD_COUNT = 10; //使用CountDownLatch让各线程同时开始 private CountDownLatch cdl = new CountDownLatch(THREAD_COUNT + 1); private int n = 0; private AtomicInteger ai = new AtomicInteger(0); private long startTime; public void init() { startTime = System.nanoTime(); } /** * 使用AtomicInteger.getAndIncrement,测试结果为1.8比1.7有明显性能提升 * @return */ private final int getAndIncreaseA() { int result = ai.getAndIncrement(); if (result == TEST_SIZE) { System.out.println(System.nanoTime() - startTime); System.exit(0); } return result; } /** * 使用synchronized来完成同步,测试结果为1.7和1.8几乎无性能差别 * @return */ private final int getAndIncreaseB() { int result; synchronized (this) { result = n++; } if (result == TEST_SIZE) { System.out.println(System.nanoTime() - startTime); System.exit(0); } return result; } /** * 使用AtomicInteger.compareAndSet在java代码层面做失败重试(与1.7的AtomicInteger.getAndIncrement的实现类似), * 测试结果为1.7和1.8几乎无性能差别 * @return */ private final int getAndIncreaseC() { int result; do { result = ai.get(); } while (!ai.compareAndSet(result, result + 1)); if (result == TEST_SIZE) { System.out.println(System.nanoTime() - startTime); System.exit(0); } return result; } public class MyTask implements Runnable { @Override public void run() { cdl.countDown(); try { cdl.await(); } catch (InterruptedException e) { e.printStackTrace(); } while (true) getAndIncreaseA();// getAndIncreaseB(); } } public static void main(String[] args) throws InterruptedException { AtomicTest at = new AtomicTest(); for (int n = 0; n < THREAD_COUNT; n++) new Thread(at.new MyTask()).start(); System.out.println("start"); at.init(); at.cdl.countDown(); } }
The following are the test results under Intel(R) Core(TM) i7-4710HQ CPU @2.50GHz (four cores and eight threads) (the fluctuation is small, so each item was only tested four or five times. Take one of the more intermediate values):
jdk1.7
AtomicInteger.getAndIncrement 12,653,757,034
synchronized 4,146,813,462
AtomicInteger.compareAndSet 12,952,821,234
jdk1.8
AtomicInteger.getAndIncrement 2,159,486,620
synchronized 4,067,309,911
AtomicInteger.compareAndSet 12,893,188,541
Supplement: At the request of netizens, Unsafe is provided here. The relevant source code of getAndAddInt and my test code.
Use jad to decompile the source code of Unsafe in jdk1.8:
public final int getAndAddInt(Object obj, long l, int i) { int j; do j = getIntVolatile(obj, l); while(!compareAndSwapInt(obj, l, j, j + i)); return j; } public native int getIntVolatile(Object obj, long l); public final native boolean compareAndSwapInt(Object obj, long l, int i, int j);
Unsafe source code of openjdk8:
public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; } public native int getIntVolatile(Object o, long offset); public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
My test code (tip: if eclipse When the IDE reports an error, it is because of the use of restricted Unsafe. You can reduce the warning level from error to warning (specifically Baidu):
... import sun.misc.Unsafe; public class AtomicTest { .... private Unsafe unsafe; private long valueOffset; public AtomicTest(){ 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 int getAndIncreaseD(){ int result; 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); } return result; } ... }
Supplementary 2: For the reasons for performance improvement, there are Although I cannot say that the following inference is 100% correct (because the source code of jvm is not used as an argument), I am still very confident. Thank you to netizen @zhoukeren@liuxinglanyue!
Unsafe is specially processed and cannot be understood as regular java code. The difference is:
When calling getAndAddInt, if the bottom layer of the system supports fetch-and-add, then it executes It is the native method, using fetch-and-add;
If it is not supported, just follow the getAndAddInt method body seen above and execute it in the form of java code, using compare-and-swap;
This also coincides with the comment above Unsafe::getAndAddInt in openjdk8:
// The following contain CAS-based Java implementations used on // platforms not supporting native instructions
The special processing of Unsafe is the "black magic" I mentioned above ".
The above is the detailed content of Detailed introduction to the enhancements of CAS in Java8. For more information, please follow other related articles on the PHP Chinese website!

Java8计算一年前或一年后的日期利用minus()方法计算一年前的日期packagecom.shxt.demo02;importjava.time.LocalDate;importjava.time.temporal.ChronoUnit;publicclassDemo09{publicstaticvoidmain(String[]args){LocalDatetoday=LocalDate.now();LocalDatepreviousYear=today.minus(1,ChronoUni

Java8如何计算一周后的日期这个例子会计算一周后的日期。LocalDate日期不包含时间信息,它的plus()方法用来增加天、周、月,ChronoUnit类声明了这些时间单位。由于LocalDate也是不变类型,返回后一定要用变量赋值。packagecom.shxt.demo02;importjava.time.LocalDate;importjava.time.temporal.ChronoUnit;publicclassDemo08{publicstaticvoidmain(String[

通过CAS(CentralAuthenticationService)实现PHP安全验证随着互联网的快速发展,用户权限管理和身份验证越来越重要。在开发WEB应用程序时,保护用户数据和防止未经授权访问是至关重要的。为了实现这一目标,我们可以使用CAS(CentralAuthenticationService)来进行PHP的安全验证。CAS

1、说明当多个线程同时对某个资源进行CAS操作时,只有一个线程成功,但不会堵塞其他线程,其他线程只会收到操作失败的信号。可见CAS其实是一个乐观的锁。2、实例跟随AtomInteger的代码,我们可以发现最终调用的是sum.misc.Unsafe。看看Unsafe这个名字,它是一个不安全的类别,它利用了Java类别和可见性规则中恰到好处的漏洞。为了速度,Unsafe在Java的安全标准上做出了一些妥协。publicfinalnativebooleancompareAndSwapInt(Objec

CAS解释:CAS(compareandswap),比较并交换。可以解决多线程并行情况下使用锁造成性能损耗的一种机制.CAS操作包含三个操作数—内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。一个线程从主内存中得到num值,并对num进行操作,写入值的时候,线程会把第一次取到的num值和主内存中num值进行比较,如果相等,就会将改变后的num写入主内存,如果不相等,则一直循环对比,知道成功为止。CAS产

有锁并发对于大多数程序员(当然我也基本上是其中一员),并发编程几乎就等价于给相关数据结构加上一个锁(Mutex)。比如如果我们需要一个支持并发的栈,那最简单的方法就是给一个单线程的栈加上锁std::sync::Mutex。(加上Arc是为了能让多个线程都拥有栈的所有权)usestd::sync::{Mutex,Arc};#[derive(Clone)]structConcurrentStack{inner:Arc,}implConcurrentStack{pubfnnew()->Self{

在Java8中获取当前的时间戳Instant类有一个静态工厂方法now()会返回当前的时间戳,如下所示:packagecom.shxt.demo02;importjava.time.Instant;publicclassDemo16{publicstaticvoidmain(String[]args){Instanttimestamp=Instant.now();System.out.println("Whatisvalueofthisinstant"+timestamp.t

Java8中如何使用预定义的格式化工具去解析或格式化日期packagecom.shxt.demo02;importjava.time.LocalDate;importjava.time.format.DateTimeFormatter;publicclassDemo17{publicstaticvoidmain(String[]args){StringdayAfterTommorrow="20180205";LocalDateformatted=LocalDate.parse


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Dreamweaver CS6
Visual web development tools

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool
