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

服務器之家:專注于服務器技術及軟件下載分享
分類導航

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

服務器之家 - 編程語言 - JAVA教程 - Java并發(fā)編程總結——慎用CAS詳解

Java并發(fā)編程總結——慎用CAS詳解

2020-05-13 14:28jingxian JAVA教程

下面小編就為大家?guī)硪黄狫ava并發(fā)編程總結——慎用CAS詳解。小編覺得挺不錯的, 現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一、CAS和synchronized適用場景

1、對于資源競爭較少的情況,使用synchronized同步鎖進行線程阻塞和喚醒切換以及用戶態(tài)內核態(tài)間的切換操作額外浪費消耗cpu資源;而CAS基于硬件實現,不需要進入內核,不需要切換線程,操作自旋幾率較少,因此可以獲得更高的性能。

2、對于資源競爭嚴重的情況,CAS自旋的概率會比較大,從而浪費更多的CPU資源,效率低于synchronized。以java.util.concurrent.atomic包中AtomicInteger類為例,其getAndIncrement()方法實現如下:

?
1
2
3
4
5
6
7
8
public final int getAndIncrement() {
    for (;;) {
      int current = get();
      int next = current + 1;
      if (compareAndSet(current, next))
        return current;
    }
}

如果compareAndSet(current, next)方法成功執(zhí)行,則直接返回;如果線程競爭激烈,導致compareAndSet(current, next)方法一直不能成功執(zhí)行,則會一直循環(huán)等待,直到耗盡cpu分配給該線程的時間片,從而大幅降低效率。

二、CAS錯誤的使用場景

?
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
36
37
38
39
40
41
42
43
44
45
46
public class CASDemo {
  private final int THREAD_NUM = 1000;
  private final int MAX_VALUE = 20000000;
  private AtomicInteger casI = new AtomicInteger(0);
  private int syncI = 0;
  private String path = "/Users/pingping/DataCenter/Books/Linux/Linux常用命令詳解.txt";
 
  public void casAdd() throws InterruptedException {
    long begin = System.currentTimeMillis();
    Thread[] threads = new Thread[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++) {
      threads[i] = new Thread(new Runnable() {
        public void run() {
          while (casI.get() < MAX_VALUE) {
            casI.getAndIncrement();
          }
        }
      });
      threads[i].start();
    }
    for (int j = 0; j < THREAD_NUM; j++) {
      threads[j].join();
    }
    System.out.println("CAS costs time: " + (System.currentTimeMillis() - begin));
  }
 
  public void syncAdd() throws InterruptedException {
    long begin = System.currentTimeMillis();
    Thread[] threads = new Thread[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++) {
      threads[i] = new Thread(new Runnable() {
        public void run() {
          while (syncI < MAX_VALUE) {
            synchronized ("syncI") {
              ++syncI;
            }
          }
        }
      });
      threads[i].start();
    }
    for (int j = 0; j < THREAD_NUM; j++)
      threads[j].join();
    System.out.println("sync costs time: " + (System.currentTimeMillis() - begin));
  }
}

在我的雙核cpu上運行,結果如下:

Java并發(fā)編程總結——慎用CAS詳解

可見在不同的線程下,采用CAS計算消耗的時間遠多于使用synchronized方式。原因在于第15行

?
1
2
3
14           while (casI.get() < MAX_VALUE) {
15             casI.getAndIncrement();
16           }

的操作是一個耗時非常少的操作,15行執(zhí)行完之后會立刻進入循環(huán),繼續(xù)執(zhí)行,從而導致線程沖突嚴重。

三、改進的CAS使用場景

為了解決上述問題,只需要讓每一次循環(huán)執(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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class CASDemo {
  private final int THREAD_NUM = 1000;
  private final int MAX_VALUE = 1000;
  private AtomicInteger casI = new AtomicInteger(0);
  private int syncI = 0;
  private String path = "/Users/pingping/DataCenter/Books/Linux/Linux常用命令詳解.txt";
 
  public void casAdd2() throws InterruptedException {
    long begin = System.currentTimeMillis();
    Thread[] threads = new Thread[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++) {
      threads[i] = new Thread(new Runnable() {
        public void run() {
          while (casI.get() < MAX_VALUE) {
            casI.getAndIncrement();
            try (InputStream in = new FileInputStream(new File(path))) {
                while (in.read() != -1);
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        }
      });
      threads[i].start();
    }
    for (int j = 0; j < THREAD_NUM; j++)
      threads[j].join();
    System.out.println("CAS Random costs time: " + (System.currentTimeMillis() - begin));
  }
 
  public void syncAdd2() throws InterruptedException {
    long begin = System.currentTimeMillis();
    Thread[] threads = new Thread[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++) {
      threads[i] = new Thread(new Runnable() {
        public void run() {
          while (syncI < MAX_VALUE) {
            synchronized ("syncI") {
              ++syncI;
            }
            try (InputStream in = new FileInputStream(new File(path))) {
              while (in.read() != -1);
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        }
      });
      threads[i].start();
    }
    for (int j = 0; j < THREAD_NUM; j++)
      threads[j].join();
    System.out.println("sync costs time: " + (System.currentTimeMillis() - begin));
  }
}

 

在while循環(huán)中,增加了一個讀取文件內容的操作,該操作大概需要耗時40ms,從而可以減少線程沖突。測試結果如下:

Java并發(fā)編程總結——慎用CAS詳解

可見在資源沖突比較小的情況下,采用CAS方式和synchronized同步效率差不多。為什么CAS相比synchronized沒有獲得更高的性能呢?

測試使用的jdk為1.7,而從jdk1.6開始,對鎖的實現引入了大量的優(yōu)化,如鎖粗化(Lock Coarsening)、鎖消除(Lock Elimination)、輕量級鎖(Lightweight Locking)、偏向鎖(Biased Locking)、適應性自旋(Adaptive Spinning)等技術來減少鎖操作的開銷。而其中自旋鎖的原理,類似于CAS自旋,甚至比CAS自旋更為優(yōu)化。具體內容請參考 深入JVM鎖機制1-synchronized。

四、總結

1、使用CAS在線程沖突嚴重時,會大幅降低程序性能;CAS只適合于線程沖突較少的情況使用。

2、synchronized在jdk1.6之后,已經改進優(yōu)化。synchronized的底層實現主要依靠Lock-Free的隊列,基本思路是自旋后阻塞,競爭切換后繼續(xù)競爭鎖,稍微犧牲了公平性,但獲得了高吞吐量。在線程沖突較少的情況下,可以獲得和CAS類似的性能;而線程沖突嚴重的情況下,性能遠高于CAS。

以上這篇Java并發(fā)編程總結——慎用CAS詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成年人黄视频在线观看 | 日本漫画被黄漫免费动 | free性丰满hd性欧美人体 | 青青草国产一区二区三区 | 波多野结衣52部合集在线观看 | 西西人体大胆77777视频 | sihu国产午夜精品一区二区三区 | 好大好硬好长好爽a网站 | 国产草草 | 亚洲欧洲色图 | 水岛津实在线 | 亚洲精品私拍国产福利在线 | 成人性色生活片免费网 | 亚洲高清视频网站 | 成人免费视频一区二区三区 | 白丝h视频 | 欧美三级不卡在线观线看高清 | 息与子中文字幕bd | 国产精品青青在线观看香蕉 | 甜蜜惩罚小说 | 女教师三级做受 | 跪趴好紧h | 男女车车好快的车车免费网站 | 色就色欧美综合偷拍区a | 国产二区视频在线观看 | 午夜影院免费体验 | 午夜理论片YY4399影院 | www.日日操| 性俄罗斯xxxxxhd | 亚洲国产精品无码中文在线 | 日韩高清在线免费看 | www在线视频在线播放 | 韩国漂亮美女三级在线观看 | 久久全国免费观看视频 | 亚洲免费在线视频 | 国产色网址| 国产精品一区牛牛影视 | 亚洲一区二区三区不卡在线播放 | 国产福利一区二区精品视频 | 欧美一区二区三区四区视频 | 韩国最新理论三级在线观看 |