最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2016年06月08日 12:13:15   投稿:jingxian  
下面小編就為大家?guī)?lái)一篇Java并發(fā)編程總結(jié)——慎用CAS詳解。小編覺(jué)得挺不錯(cuò)的, 現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

一、CAS和synchronized適用場(chǎng)景

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

2、對(duì)于資源競(jìng)爭(zhēng)嚴(yán)重的情況,CAS自旋的概率會(huì)比較大,從而浪費(fèi)更多的CPU資源,效率低于synchronized。以java.util.concurrent.atomic包中AtomicInteger類為例,其getAndIncrement()方法實(shí)現(xiàn)如下:

public final int getAndIncrement() {
    for (;;) {
      int current = get();
      int next = current + 1;
      if (compareAndSet(current, next))
        return current;
    }
}

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

二、CAS錯(cuò)誤的使用場(chǎng)景

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上運(yùn)行,結(jié)果如下:

可見(jiàn)在不同的線程下,采用CAS計(jì)算消耗的時(shí)間遠(yuǎn)多于使用synchronized方式。原因在于第15行

14           while (casI.get() < MAX_VALUE) {
15             casI.getAndIncrement();
16           }

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

三、改進(jìn)的CAS使用場(chǎng)景

為了解決上述問(wèn)題,只需要讓每一次循環(huán)執(zhí)行的時(shí)間變長(zhǎng),即可以大幅減少線程沖突。修改代碼如下:

 

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)中,增加了一個(gè)讀取文件內(nèi)容的操作,該操作大概需要耗時(shí)40ms,從而可以減少線程沖突。測(cè)試結(jié)果如下:

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

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

四、總結(jié)

1、使用CAS在線程沖突嚴(yán)重時(shí),會(huì)大幅降低程序性能;CAS只適合于線程沖突較少的情況使用。

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

以上這篇Java并發(fā)編程總結(jié)——慎用CAS詳解就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

巩留县| 合江县| 清涧县| 康定县| 静宁县| 荆州市| 朔州市| 寿阳县| 丰原市| 临朐县| 永川市| 安泽县| 邢台县| 平安县| 新疆| 临安市| 江永县| 华坪县| 密山市| 凭祥市| 紫阳县| 昭苏县| 阳山县| 武穴市| 类乌齐县| 崇明县| 商丘市| 莲花县| 广德县| 宣城市| 萨嘎县| 望谟县| 英山县| 杂多县| 安化县| 射阳县| 五台县| 新野县| 衡南县| 嘉兴市| 宜川县|