前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java Concurrent Atomic实现原理&源码解读(JDK 10)

Java Concurrent Atomic实现原理&源码解读(JDK 10)

作者头像
邹志全
发布2019-07-31 10:34:15
7500
发布2019-07-31 10:34:15
举报
文章被收录于专栏:EffectiveCodingEffectiveCoding

JDK 10,可以说是很新了,比起JDK 8更新了不少实现,比如说下面会讲到VarHandle

说了这么多篇原理类的,终于要开始看源码了。这一篇描述atomic,主要简述Concurrent里面的核心使用的类,其他相关的,大家看的时候可以顺便进去看两眼内容不多,还可以。

是时候看一眼JDK了,忽然发现IDEA可能是读源码最好用的工具了,sun包的暂时不看就单说Concurrent里面的 。

image.png

AtomicBoolean、AtomicInteger等是atomic中比较经典的一类,这里不描述API,就单说源码实现。

AtomicBoolean

首先看到的是:

代码语言:javascript
复制
public class AtomicBoolean implements java.io.Serializable {
    private static final long serialVersionUID = 4654671469794556979L;
    private static final VarHandle VALUE;
    static {
        try {
            MethodHandles.Lookup l = MethodHandles.lookup();
            VALUE = l.findVarHandle(AtomicBoolean.class, "value", int.class);
        } catch (ReflectiveOperationException e) {
            throw new Error(e);
        }
    }

不仅是AtomicBoolean,其他的原子类也都是可序列化,并且持有一个通过JNI调用本地方法的VarHandle,这个类实在sun.lang里实现的,也不复杂有兴趣可以去看看。首先完成静态属性的初始化,(这里可以顺道提一点类的初始化顺序:父类静态变量,父类静态初始化块,子类静态变量,子类静态初始化块,非静态属性与之相同。父类先于子类,静态属性是在载入类是就已经初始化了。) 再往下看:

代码语言:javascript
复制
private volatile int value;

一个非对象类型的volatile int value值,这个值是整个AtomicBoolean逻辑的核心,后续的实现的功能函数都会围绕它展开。1:true 0:false,同时volatile避免的必要是的可见性及防止重排序。

代码语言:javascript
复制
/**
* Creates a new {@code AtomicBoolean} with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicBoolean(boolean initialValue) {
    value = initialValue ? 1 : 0;
}
/**
* Creates a new {@code AtomicBoolean} with initial value {@code false}.
*/
public AtomicBoolean() {
}

这个是构造函数,可以清晰看到value的使用。

代码语言:javascript
复制
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
public final boolean get() {
    return value != 0;
}

get函数直接返回就ok,因为是volatile,volatile的直接写操作是原子的,保证了return的值绝对是各线程更新后最新的,不存在在工作内存为刷入主存,而导致的value值不一致的情况。问题不大,继续向下:

代码语言:javascript
复制
/**
* Atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(boolean expectedValue, boolean newValue) {
    return VALUE.compareAndSet(this,
                               (expectedValue ? 1 : 0),
                               (newValue ? 1 : 0));
}

这里开始使用JNI调用本地函数了,进到源码里看一眼:这里我就不放注释了,着实太长。(这个方法在VarHandle里)

代码语言:javascript
复制
public final native
@MethodHandle.PolymorphicSignature
@HotSpotIntrinsicCandidate
boolean compareAndSet(Object... args);

可以看到修饰这个函数的关键词,native 关键词,native主要有两个作用 1、JDK依赖于C++函数直接完成某些系统调用及函数. 2、Java C++联合开发时,可以顺道调用C++工具函数,当然了驱动外部程序现在有了ProcessBuilder但是两者还是存在很大区别,JNI是直接调用的函数,而ProcessBuilder是完成外部完整程序的运行,比如说一条shell,一个Cpp文件,给我们直观的感受是开了个进程。 这里native 的使用场景,完全符合第一种场景。

Java 8及之前底层能保证比较并操作原子性的方式有这么几种:(因为在底层讨论,所以AtomicInteger属于上层实现了,这里不算是一种,但在上层应用中还是算一种原子的)

1、使用原子性的FieldUpdaters,利用了反射机制,操作开销也会更大; 2、使用sun.misc.Unsafe提供的JVM内置函数API,虽然这种方式比较快,但它会损害安全性和可移植性。 在Java 9时出现了VarHandle来部分替代java.util.concurrent.atomicsun.misc.Unsafe

VarHandle 可以与任何字段、数组元素或静态变量关联,支持在不同访问模型下对这些类型变量的访问,包括简单的 read/write 访问,volatile 类型的 read/write 访问,和 CAS(compare-and-swap)等。虽然unsafe仍旧保留使用,但Java 9之后用的大部分就都是VarHandle了,官方称为变量句柄,然后VarHandle依赖于VarForm使用,然后VarForm包含一下两个变量及相关操作以完成VarHandle的支持。

代码语言:javascript
复制
final @Stable MethodType[] methodType_table;
final @Stable MemberName[] memberName_table;

主要支持链接所有签名的多态方法,注意compare的第一个注解。 然后第二个注解的含义: 如果使用@SetNativeMethodPrefix注解本地方法,run的时候就会得到一个警告。 比如:

代码语言:javascript
复制
For instance for Thread::isInterrupted:
Compiler intrinsic is defined for method
[java.lang.Thread.isInterrupted(Z)Z], but the method is not annotated with
@HotSpotIntrinsicCandidate. Method will not be inlined.

然后boolean类型原子性的保证到这里就看完了。

AtomicInteger

代码语言:javascript
复制
public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;
    /*
     * This class intended to be implemented using VarHandles, but there
     * are unresolved cyclic startup dependencies.
     */
    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
    private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");
    private volatile int value;

跟boolean一样,支持序列化,同样维护着一个private volatile int value不同的是AtomicInteger是依赖于UnSafe调用外部方法实现的

下面是Unsafe中compareAndSet的实现:

代码语言:javascript
复制
/**
* Atomically updates Java variable to {@code x} if it is currently
* holding {@code expected}.
*
* <p>This operation has memory semantics of a {@code volatile} read
* and write.  Corresponds to C11 atomic_compare_exchange_strong.
*
* @return {@code true} if successful
*/
@HotSpotIntrinsicCandidate
public final native boolean compareAndSetInt(Object o, long offset,
                                             int expected,
                                             int x);

同样调用本地方法,不多赘述。 其他方法的使用,不如说+1、-1等看官方API就可以了,底层的函数比较简单通俗易懂。

Atomic*Array

基于VarHandle实现,其中维护了一个数组对象,但是相对于其他对象来说,使用了MethodHandles.arrayElementVarHandle(int[].class)来完成初始。

代码语言:javascript
复制
public class AtomicIntegerArray implements java.io.Serializable {
    private static final long serialVersionUID = 2862133569453604235L;
    private static final VarHandle AA
        = MethodHandles.arrayElementVarHandle(int[].class);
    private final int[] array;

其中所调用的本地方法也与其他不同,volatile相关特性依赖于native函数实现。

代码语言:javascript
复制
public final native
@MethodHandle.PolymorphicSignature
@HotSpotIntrinsicCandidate
Object getVolatile(Object... args);

AtomicBoolean:VarHandle AtomicInteger:UnSafe AtomicLong:UnSafe AtomicReference:Varhandle,但与AtomicBoolean不同的是AtomicReference多了一个泛型处理。 Atomic里面的实现总来说就是这样的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.07.15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • AtomicBoolean
  • AtomicInteger
  • Atomic*Array
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档