原子变量 java_Java原子变量详解
實現(xiàn)全局自增id最簡單有效的方式是什么? java.util.concurrent.atomic 包定義了一些常見類型的原子變量。這些原子變量為我們提供了一種操作單一變量無鎖( lock-free )的線程安全( thread-safe )方式。實際上該包下面的類為我們提供了類似 volatile 變量的特性,同時還提供了諸如 boolean compareAndSet(expectedValue, updateValue) 的功能。不使用鎖實現(xiàn)線程安全聽起來似乎很不可思議,這其實是通過CPU的compare and swap指令實現(xiàn)的,由于硬件指令支持當然不需要加鎖了。
先不去討論這些細節(jié),我們來看一下原子變量的用法。一個典型的用法是可以使用原子變量輕松實現(xiàn)全局自增id,就像下面這樣:
// 線程安全的序列id生成器
class Sequencer {
private final AtomicLong sequenceNumber = new AtomicLong(0);
publiclongnext() {
return sequenceNumber.getAndIncrement();
}
}
上述代碼利用AtomicLong創(chuàng)建了一個Sequencer類,不斷調(diào)用該類的next()方法就可以得到線程安全的自增id,用起來非常簡單直觀。下面我們給出每種原子變量類型的用法說明。
AtomicInteger and AtomicLong
AtomicInteger 和 AtomicLong 分別代表原子類型的整型和長整型,這兩個類提供十分相似的功能,僅僅是位寬不同。如上例所示,原子整型可用于多線程下全局自增id,除此之外還提供了原子 比較-賦值 等操作,諸如 compareAndSet(expect, update) , decrementAndGet() , getAndDecrement() , getAndSet(newValue) 等等,更全面的接口描述可參考JDK文檔。需要提醒的是這些函數(shù)都是通過原子CPU指令實現(xiàn),執(zhí)行效率較高。
原子整型看似跟普通整型( Integer, Long )類型相似,但不能使用原子整型替代普通整型,因為原子整型是可變的,而普通整型不可變。由于這個原因,使用原子整型作為Map的key并不是個好主意。
你可能會想當然的以為應(yīng)該有 AtomicFloat 和 AtomicDouble ,遺憾的是類庫里并沒有這兩個類型, AtomicByte 和 AtomicShort 也沒有。如果需要替代方案是使用 AtomicInteger 和 AtomicLong 。可通過 Float.floatToRawIntBits(float) 和 Float.intBitsToFloat(int) 將Float存儲到 AtomicInteger 中,類似的Double類型也可以存儲到 AtomicLong 中。
AtomicReference
AtomicReference 用于存放一個可以原子更新的對象引用。該類包含 get() , set() , compareAndSet() , getAndSet() 等原子方法來獲取和更新其代表的對象引用。
AtomicXXXArray
atomic包下面有三種原子數(shù)組: AtomicIntegerArray , AtomicLongArra , AtomicReferenceArray ,分別代表整型、長整型和引用類型的原子數(shù)組。原子數(shù)組使得我們可以線程安全的方式去修改和訪問數(shù)組里的單個元素。簡單示例如下:
// 原子數(shù)組示例
AtomicLongArray longArray = new AtomicLongArray(10);// 創(chuàng)建長度為10的原子數(shù)組
longArray.set(1, 100);
long v = longArray.getAndIncrement(1);
AtomicReferenceArray referenceArray = new AtomicReferenceArray<>(16);
referenceArray.set(3, "love");
referenceArray.compareAndSet(3, "love", "you");
簡單來說原子數(shù)組就是一種支持線程安全的數(shù)組,仍然具有數(shù)組“定長”的性質(zhì),如果訪問元素超過了數(shù)組的長度,將會拋出 IndexOutOfBoundsException 。你可能已經(jīng)想到了,可以使用線程安全的容器來避免容量不足,我們會在后續(xù)章節(jié)介紹。
什么是線程安全?
線程安全是指多線程訪問是時,無論線程的調(diào)度策略是什么,程序能夠正確的執(zhí)行。導(dǎo)致線程不安全的一個原因是狀態(tài)不一致,如果線程A修改了某個共享變量(比如給id++),而線程B沒有及時知道,就會導(dǎo)致B在錯誤的狀態(tài)上執(zhí)行,結(jié)果的正確性也就無法保證。原子變量為我們提供了一種保證單個狀態(tài)一致的簡單方式,一個線程修改了原子變量,另外的線程立即就能看到,這比通過鎖實現(xiàn)的方式效率要高;如果要同時保證多個變量狀態(tài)一致,就只能使用鎖了。
歡迎加入學(xué)習(xí)交流群569772982,大家一起學(xué)習(xí)交流。
總結(jié)
以上是生活随笔為你收集整理的原子变量 java_Java原子变量详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 前索引_MySQL查询性能优
- 下一篇: 南京理工大学计算机学院教师信息网,南京理