JDK 10囊卜,可以說是很新了,比起JDK 8更新了不少實(shí)現(xiàn)邑闺,比如說下面會講到VarHandle
說了這么多篇原理類的,終于要開始看源碼了棕兼。這一篇描述atomic陡舅,主要簡述Concurrent里面的核心使用的類,其他相關(guān)的伴挚,大家看的時候可以順便進(jìn)去看兩眼內(nèi)容不多靶衍,還可以。
是時候看一眼JDK了茎芋,忽然發(fā)現(xiàn)IDEA可能是讀源碼最好用的工具了摊灭,sun包的暫時不看就單說Concurrent里面的 。
AtomicBoolean败徊、AtomicInteger
等是atomic中比較經(jīng)典的一類,這里不描述API掏缎,就單說源碼實(shí)現(xiàn)皱蹦。
AtomicBoolean
首先看到的是:
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調(diào)用本地方法的VarHandle沪哺,這個類實(shí)在sun.lang里實(shí)現(xiàn)的,也不復(fù)雜有興趣可以去看看酌儒。首先完成靜態(tài)屬性的初始化辜妓,(這里可以順道提一點(diǎn)類的初始化順序:父類靜態(tài)變量,父類靜態(tài)初始化塊,子類靜態(tài)變量籍滴,子類靜態(tài)初始化塊酪夷,非靜態(tài)屬性與之相同。父類先于子類孽惰,靜態(tài)屬性是在載入類是就已經(jīng)初始化了晚岭。)
再往下看:
private volatile int value;
一個非對象類型的volatile int value值,這個值是整個AtomicBoolean邏輯的核心勋功,后續(xù)的實(shí)現(xiàn)的功能函數(shù)都會圍繞它展開坦报。1:true 0:false,同時volatile避免的必要是的可見性及防止重排序狂鞋。
/**
* 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() {
}
這個是構(gòu)造函數(shù)片择,可以清晰看到value的使用。
/**
* 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函數(shù)直接返回就ok骚揍,因?yàn)槭莢olatile字管,volatile的直接寫操作是原子的,保證了return的值絕對是各線程更新后最新的疏咐,不存在在工作內(nèi)存為刷入主存纤掸,而導(dǎo)致的value值不一致的情況。問題不大浑塞,繼續(xù)向下:
/**
* 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調(diào)用本地函數(shù)了借跪,進(jìn)到源碼里看一眼:這里我就不放注釋了,著實(shí)太長酌壕。(這個方法在VarHandle里)
public final native
@MethodHandle.PolymorphicSignature
@HotSpotIntrinsicCandidate
boolean compareAndSet(Object... args);
可以看到修飾這個函數(shù)的關(guān)鍵詞掏愁,native 關(guān)鍵詞,native主要有兩個作用
1卵牍、JDK依賴于C++函數(shù)直接完成某些系統(tǒng)調(diào)用及函數(shù).
2果港、Java C++聯(lián)合開發(fā)時,可以順道調(diào)用C++工具函數(shù)糊昙,當(dāng)然了驅(qū)動外部程序現(xiàn)在有了ProcessBuilder
但是兩者還是存在很大區(qū)別辛掠,JNI
是直接調(diào)用的函數(shù),而ProcessBuilder
是完成外部完整程序的運(yùn)行释牺,比如說一條shell萝衩,一個Cpp文件,給我們直觀的感受是開了個進(jìn)程没咙。
這里native 的使用場景猩谊,完全符合第一種場景。
Java 8及之前底層能保證比較并操作原子性的方式有這么幾種:(因?yàn)樵诘讓佑懻摷栏眨訟tomicInteger屬于上層實(shí)現(xiàn)了牌捷,這里不算是一種墙牌,但在上層應(yīng)用中還是算一種原子的)
1、使用原子性的FieldUpdaters
暗甥,利用了反射機(jī)制喜滨,操作開銷也會更大;
2淋袖、使用sun.misc.Unsafe
提供的JVM內(nèi)置函數(shù)API鸿市,雖然這種方式比較快,但它會損害安全性和可移植性即碗。
在Java 9時出現(xiàn)了VarHandle來部分替代java.util.concurrent.atomic
和sun.misc.Unsafe
焰情。
VarHandle 可以與任何字段、數(shù)組元素或靜態(tài)變量關(guān)聯(lián)剥懒,支持在不同訪問模型下對這些類型變量的訪問内舟,包括簡單的 read/write 訪問,volatile 類型的 read/write 訪問初橘,和 CAS(compare-and-swap)等验游。雖然unsafe仍舊保留使用,但Java 9之后用的大部分就都是VarHandle了保檐,官方稱為變量句柄耕蝉,然后VarHandle依賴于VarForm使用,然后VarForm包含一下兩個變量及相關(guān)操作以完成VarHandle的支持夜只。
final @Stable MethodType[] methodType_table;
final @Stable MemberName[] memberName_table;
主要支持鏈接所有簽名的多態(tài)方法垒在,注意compare的第一個注解。
然后第二個注解的含義:
如果使用@SetNativeMethodPrefix注解本地方法扔亥,run的時候就會得到一個警告场躯。
比如:
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
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一樣旅挤,支持序列化踢关,同樣維護(hù)著一個private volatile int value
,不同的是AtomicInteger是依賴于UnSafe調(diào)用外部方法實(shí)現(xiàn)的粘茄。
下面是Unsafe中compareAndSet的實(shí)現(xiàn):
/**
* 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);
同樣調(diào)用本地方法签舞,不多贅述。
其他方法的使用柒瓣,不如說+1瘪菌、-1等看官方API就可以了,底層的函數(shù)比較簡單通俗易懂嘹朗。
Atomic*Array
基于VarHandle實(shí)現(xiàn),其中維護(hù)了一個數(shù)組對象诵肛,但是相對于其他對象來說屹培,使用了MethodHandles.arrayElementVarHandle(int[].class)
來完成初始默穴。
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;
其中所調(diào)用的本地方法也與其他不同,volatile相關(guān)特性依賴于native函數(shù)實(shí)現(xiàn)褪秀。
public final native
@MethodHandle.PolymorphicSignature
@HotSpotIntrinsicCandidate
Object getVolatile(Object... args);
AtomicBoolean
:VarHandle
AtomicInteger
:UnSafe
AtomicLong
:UnSafe
AtomicReference
:Varhandle蓄诽,但與AtomicBoolean不同的是AtomicReference多了一個泛型處理。
Atomic里面的實(shí)現(xiàn)總來說就是這樣的媒吗。