一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語(yǔ)言 - JAVA教程 - Java 高并發(fā)十: JDK8對(duì)并發(fā)的新支持詳解

Java 高并發(fā)十: JDK8對(duì)并發(fā)的新支持詳解

2020-06-15 11:31Hosee JAVA教程

本文主要介紹Java 高并發(fā)JDK8的支持,這里整理了詳細(xì)的資料及1. LongAdder 2. CompletableFuture 3. StampedLock的介紹,有興趣的小伙伴可以參考下

1. LongAdder

和AtomicLong類似的使用方式,但是性能比AtomicLong更好。

LongAdder與AtomicLong都是使用了原子操作來(lái)提高性能。但是LongAdder在AtomicLong的基礎(chǔ)上進(jìn)行了熱點(diǎn)分離,熱點(diǎn)分離類似于有鎖操作中的減小鎖粒度,將一個(gè)鎖分離成若干個(gè)鎖來(lái)提高性能。在無(wú)鎖中,也可以用類似的方式來(lái)增加CAS的成功率,從而提高性能。

LongAdder原理圖:

Java 高并發(fā)十: JDK8對(duì)并發(fā)的新支持詳解

AtomicLong的實(shí)現(xiàn)方式是內(nèi)部有個(gè)value 變量,當(dāng)多線程并發(fā)自增,自減時(shí),均通過(guò)CAS 指令從機(jī)器指令級(jí)別操作保證并發(fā)的原子性。唯一會(huì)制約AtomicLong高效的原因是高并發(fā),高并發(fā)意味著CAS的失敗幾率更高, 重試次數(shù)更多,越多線程重試,CAS失敗幾率又越高,變成惡性循環(huán),AtomicLong效率降低。

而LongAdder將把一個(gè)value拆分成若干cell,把所有cell加起來(lái),就是value。所以對(duì)LongAdder進(jìn)行加減操作,只需要對(duì)不同的cell來(lái)操作,不同的線程對(duì)不同的cell進(jìn)行CAS操作,CAS的成功率當(dāng)然高了(試想一下3+2+1=6,一個(gè)線程3+1,另一個(gè)線程2+1,最后是8,LongAdder沒(méi)有乘法除法的API)。

可是在并發(fā)數(shù)不是很高的情況,拆分成若干的cell,還需要維護(hù)cell和求和,效率不如AtomicLong的實(shí)現(xiàn)。LongAdder用了巧妙的辦法來(lái)解決了這個(gè)問(wèn)題。

初始情況,LongAdder與AtomicLong是相同的,只有在CAS失敗時(shí),才會(huì)將value拆分成cell,每失敗一次,都會(huì)增加cell的數(shù)量,這樣在低并發(fā)時(shí),同樣高效,在高并發(fā)時(shí),這種“自適應(yīng)”的處理方式,達(dá)到一定cell數(shù)量后,CAS將不會(huì)失敗,效率大大提高。

LongAdder是一種以空間換時(shí)間的策略。

2. CompletableFuture

實(shí)現(xiàn)CompletionStage接口(40余個(gè)方法),大多數(shù)方法多數(shù)應(yīng)用在函數(shù)式編程中。并且支持流式調(diào)用

CompletableFuture是Java 8中對(duì)Future的增強(qiáng)版

簡(jiǎn)單實(shí)現(xiàn):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.concurrent.CompletableFuture;
 
public class AskThread implements Runnable {
 CompletableFuture<Integer> re = null;
 
 public AskThread(CompletableFuture<Integer> re) {
 this.re = re;
 }
 
 @Override
 public void run() {
 int myRe = 0;
 try {
 myRe = re.get() * re.get();
 } catch (Exception e) {
 }
 System.out.println(myRe);
 }
 
 public static void main(String[] args) throws InterruptedException {
 final CompletableFuture<Integer> future = new CompletableFuture<Integer>();
 new Thread(new AskThread(future)).start();
 // 模擬長(zhǎng)時(shí)間的計(jì)算過(guò)程
 Thread.sleep(1000);
 // 告知完成結(jié)果
 future.complete(60);
 }
}

Future最令人詬病的就是要等待,要自己去檢查任務(wù)是否完成了,在Future中,任務(wù)完成的時(shí)間是不可控的。而 CompletableFuture的最大改進(jìn)在于,任務(wù)完成的時(shí)間也開(kāi)放了出來(lái)。

future.complete(60);

用來(lái)設(shè)置完成時(shí)間。

CompletableFuture的異步執(zhí)行:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public static Integer calc(Integer para) {
 try {
 // 模擬一個(gè)長(zhǎng)時(shí)間的執(zhí)行
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 }
 return para * para;
 }
 
 public static void main(String[] args) throws InterruptedException,
 ExecutionException {
 final CompletableFuture<Integer> future = CompletableFuture
 .supplyAsync(() -> calc(50));
 System.out.println(future.get());
 }
CompletableFuture的流式調(diào)用:
 
public static Integer calc(Integer para) {
 try {
 // 模擬一個(gè)長(zhǎng)時(shí)間的執(zhí)行
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 }
 return para * para;
 }
 
 public static void main(String[] args) throws InterruptedException,
 ExecutionException {
 CompletableFuture<Void> fu = CompletableFuture
 .supplyAsync(() -> calc(50))
 .thenApply((i) -> Integer.toString(i))
 .thenApply((str) -> "\"" + str + "\"")
 .thenAccept(System.out::println);
 fu.get();
 }

組合多個(gè)CompletableFuture:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static Integer calc(Integer para) {
 return para / 2;
 }
 
 public static void main(String[] args) throws InterruptedException,
 ExecutionException {
 CompletableFuture<Void> fu = CompletableFuture
 .supplyAsync(() -> calc(50))
 .thenCompose(
  (i) -> CompletableFuture.supplyAsync(() -> calc(i)))
 .thenApply((str) -> "\"" + str + "\"")
 .thenAccept(System.out::println);
 fu.get();
 }

這幾個(gè)例子更多是側(cè)重Java8的一些新特性,這里就簡(jiǎn)單舉下例子來(lái)說(shuō)明特性,就不深究了。
CompletableFuture跟性能上關(guān)系不大,更多的是為了支持函數(shù)式編程,在功能上的增強(qiáng)。當(dāng)然開(kāi)放了完成時(shí)間的設(shè)置是一大亮點(diǎn)。

3. StampedLock

在上一篇中剛剛提到了鎖分離,而鎖分離的重要的實(shí)現(xiàn)就是ReadWriteLock。而StampedLock則是ReadWriteLock的一個(gè)改進(jìn)。StampedLock與ReadWriteLock的區(qū)別在于,StampedLock認(rèn)為讀不應(yīng)阻塞寫,StampedLock認(rèn)為當(dāng)讀寫互斥的時(shí)候,讀應(yīng)該是重讀,而不是不讓寫線程寫。這樣的設(shè)計(jì)解決了讀多寫少時(shí),使用ReadWriteLock會(huì)產(chǎn)生寫線程饑餓現(xiàn)象。

所以StampedLock是一種偏向于寫線程的改進(jìn)。

StampedLock示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.concurrent.locks.StampedLock;
 
public class Point {
 private double x, y;
 private final StampedLock sl = new StampedLock();
 
 void move(double deltaX, double deltaY) { // an exclusively locked method
 long stamp = sl.writeLock();
 try {
 x += deltaX;
 y += deltaY;
 } finally {
 sl.unlockWrite(stamp);
 }
 }
 
 double distanceFromOrigin() { // A read-only method
 long stamp = sl.tryOptimisticRead();
 double currentX = x, currentY = y;
 if (!sl.validate(stamp)) {
 stamp = sl.readLock();
 try {
 currentX = x;
 currentY = y;
 } finally {
 sl.unlockRead(stamp);
 }
 }
 return Math.sqrt(currentX * currentX + currentY * currentY);
 }
}

上述代碼模擬了寫線程和讀線程, StampedLock根據(jù)stamp來(lái)查看是否互斥,寫一次stamp變?cè)黾幽硞€(gè)值

tryOptimisticRead()

就是剛剛所說(shuō)的讀寫不互斥的情況。

每次讀線程要讀時(shí),會(huì)先判斷

if (!sl.validate(stamp))

validate中會(huì)先查看是否有寫線程在寫,然后再判斷輸入的值和當(dāng)前的 stamp是否相同,即判斷是否讀線程將讀到最新的數(shù)據(jù)。

如果有寫線程在寫,或者 stamp數(shù)值不同,則返回失敗。

如果判斷失敗,當(dāng)然可以重復(fù)的嘗試去讀,在示例代碼中,并沒(méi)有讓其重復(fù)嘗試讀,而采用的是將樂(lè)觀鎖退化成普通的讀鎖去讀,這種情況就是一種悲觀的讀法。

stamp = sl.readLock();

StampedLock的實(shí)現(xiàn)思想:

CLH自旋鎖:當(dāng)鎖申請(qǐng)失敗時(shí),不會(huì)立即將讀線程掛起,在鎖當(dāng)中會(huì)維護(hù)一個(gè)等待線程隊(duì)列,所有申請(qǐng)鎖,但是沒(méi)有成功的線程都記錄在這個(gè)隊(duì)列中。每一個(gè)節(jié)點(diǎn)(一個(gè)節(jié)點(diǎn)代表一個(gè)線程),保存一個(gè)標(biāo)記位(locked),用于判斷當(dāng)前線程是否已經(jīng)釋放鎖。當(dāng)一個(gè)線程試圖獲得鎖時(shí),取得當(dāng)前等待隊(duì)列的尾部節(jié)點(diǎn)作為其前序節(jié)點(diǎn)。并使用類似如下代碼判斷前序節(jié)點(diǎn)是否已經(jīng)成功釋放鎖

while (pred.locked) {  
}

這個(gè)循環(huán)就是不斷等前面那個(gè)結(jié)點(diǎn)釋放鎖,這樣的自旋使得當(dāng)前線程不會(huì)被操作系統(tǒng)掛起,從而提高了性能。
當(dāng)然不會(huì)進(jìn)行無(wú)休止的自旋,會(huì)在若干次自旋后掛起線程。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久理论片 | 2021日本三级理论影院 | 窝窝影院午夜色在线视频 | 午夜理论片日本中文在线 | 白丝爆动漫羞羞动漫网站 | 欧美一区二区福利视频 | 91麻豆制片厂 | 无码精品AV久久久奶水 | 国内精品国语自产拍在线观看55 | 国产午夜精品一区二区 | 欧美日韩国产一区二区三区在线观看 | 91精品手机国产在线观 | 免费观看成年人视频 | 国语自产自拍秒拍在线视频 | 男人和女人上床 | 日本理论片中文在线观看2828 | 免费观看俄罗斯特黄特色 | 日韩天堂网 | www青青草原 | 亚洲高清色图 | 亚洲国产成人久久99精品 | 成人免费淫片95视频观看网站 | 青青草原手机在线视频 | 免费国产高清精品一区在线 | a亚洲天堂 | 色吧 | 国产亚洲玖玖玖在线观看 | 亚洲国产精品无码中文字幕 | 毛片亚洲毛片亚洲毛片 | bbc japanese黑人强行 | 操儿子| 欧美日韩国产亚洲一区二区 | 国产精品久久久久久五月尺 | 国产成人免费a在线资源 | 亚洲精品一区二区三区中文字幕 | 亚洲成人一区在线 | 国产麻豆麻豆 | 日韩免费一区 | 日本免费高清在线观看播放 | 精品一区视频 | 午夜影视免费 |