1.原子值
java5開始,提供了一些原子操作的類,如AtomicInteger、AtomicLong等
這些類提供了諸如incrementAndGet這樣的原子操作方法。
單數如果想進行複雜操作,則需要使用compareAndSet進行循環處理
在java8中提供了updateAndGet和accumulateAndGet方法
atomicLong,updateAndGet(x -> Max.max(x, observed));
atomicLong.accumulateAndGet(observed, Math::max);
同時也提供了傳回原始值的對應方法:getAndUpdate、getAndAccumulate
------------------------------------------------------
當大量線程通路同一個原始值時,由于樂觀鎖重試次數太多會導緻性能下降
Java8為此提供了LongAdder和LongAccumulator解決該問題
其思想為将初始值變為多個中立元素,計算時不同線程可以對不同元素進行操作,最後再将操作結果合并。
例如:
此時在LongAccumulator 中包含多個中立元素a1,a2...aN.該例子下中立元素初始值都為零。當調用accumulate方法累加value時,這些變量的其中之一被更新為ai = ai op v。在這個實力中ai = ai + v;
而最後調用get方法的時候,結果為a1 op a2 op ... aN. 在上述例子中為a1+a2+...aN
java8中還添加了StampedLock類實作樂觀讀
調用tryOptimisticRead方法時會擷取一個印戳,當讀取值并檢測印戳有效,則可以使用這個值,否則會獲得一個阻塞所有寫鎖的讀鎖
例:
2.ConcurrentHashMap改進
1. 更新值
concurrentHashMap在更新數值的時候雖然是線程安全的,但是在計算更新值的時候由于不能保證線程安全,更新的值可能是錯誤的。
一種補救措施是使用replace
此外還可以使用利用原子對象,例如CuncurrentHashMap<String, LongAdder>
如果需要複雜計算,compute方法可以通過一個函數來計算新的值
xxxIfPresent和xxxIfAbsent方法分别表示已經存在值或者尚未存在值的情況下才進行操作
merge方法可以在key第一次加入時做一些特殊操作,第二個參數表示鍵尚未存在時的初始值
--------------------------------------------------------------------------
2. 批量資料操作
・search會對每個鍵值對領用一個函數,直到函數傳回非null,search會終止并傳回函數結果
・reduce會通過提供的累計函數,将所有鍵值對組合起來
・foreach會對所有鍵值對應用一個函數
每個操作都有4個版本:
• operation Keys : 對鍵操作
• operation Values : 對值操作
• operation: 對鍵和值操作
• operation Entries : 對 Map.Entry 對象操作.
以search為例,有以下幾個方法:
U searchKeys(long threshold, BiFunction<? super K, ? extends U> f)
U searchValues(long threshold, BiFunction<? super V, ? extends U> f)
U search(long threshold, BiFunction<? super K, ? super V,? extends U> f)
U searchEntries(long threshold, BiFunction<Map.Entry<K, V>, ? extends U> f)
threshold為并行閥值,如果包含的元素數量超過閥值,操作會以并行方式執行,如果希望永遠以單線程執行,請使用Long.MAX_VALUE
foreach和reduce方法除了上述形式外,還有另一種形式,可以提供一個轉換器函數,首先會應用轉換器函數,然後再将結果傳遞給消費者函數
對于int、long和double,reduce操作提供了專門的方法。以toXXX開頭,需要将輸入值轉換為原始類型值,并指定一個預設值和累加器函數
-----------------------------------------------------------------------------
3. Set視圖
java8沒有提供concurrenHashSet類,但是可以通過concurrentHashMap類通過虛假值獲得一個映射
靜态方法newKeySet會傳回一個Set<K>對象,它實際上是對ConcurrentHashMap<K, Boolean>對象的封裝。
如果你已經有一個映射,keySet方法會傳回所有鍵的Set,但是你不能向這個set中添加元素,因為無法向map添加相應的值
于是,一個接收預設值的keySet方法可以解決上述問題,通過這個預設值向set中添加元素
key=java, value = 1L
3.并行數組操作
Arrays提供許多并行化操作
parallelSort可以進行并行排序,并且可以指定範圍
1 values.parallelSort(values.length / 2, values.length); // 對上半部排序
parallelSetAll方法會根據提供的計算函數對參數values的每一個值進行計算并更新
parallelPrefix将數組中每個元素替換為指定關聯操作字首的積累
假設array [1, 2, 3, 4, ...],執行完Arrays.parallelPrefix(values, (x, y) -> x * y)之後,array的結果為
[1, 1 × 2, 1 × 2 × 3, 1 × 2 × 3 × 4, ...]
4.可完成的Future
在過去,Future擷取結果的方法為get,并且調用後會一直阻塞等待get傳回結果
CompletableFuture<T>提供了“當結果可用時,再按照提供的方式處理”的功能
thenApply方法不會被阻塞,它會傳回另一個Future對象,當第一個Future對象完成時,它的結果會發給getLinks方法
Future流水線類似Steam流水線,經過一個或多個轉換過程,最後由一個終止操作結束。
如下代碼可以啟動一個流水線
另外還有一個runAsync方法,接收Runnable參數,傳回CompletableFuture<void>
接下來可以調用thenApply或者thenApplyAsync方法,在同一個線程或者另一個線程中運作另一個操作。
最終這些步驟執行完畢,需要将結果儲存在某個地方,需要一個終止操作,例如:
thenAccept方法接收一個Consumer接口(傳回類型為void),理想情況下不需要調用Future的get方法
以下是一些常用方法:

thenCompose方法做的事就是,假設同時有兩個調用鍊,T->CompletableFuture<U>和U->CompletableFuture<V>在連續調用的情況下,合并為T->CompletableFuture<V>
類似的常用方法如下: