真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

volatile和synchronized的區(qū)別是什么

本篇文章給大家分享的是有關(guān)volatile和synchronized的區(qū)別是什么,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

成都創(chuàng)新互聯(lián)公司專注于企業(yè)網(wǎng)絡(luò)營銷推廣、網(wǎng)站重做改版、臨城網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、H5建站、商城網(wǎng)站建設(shè)、集團公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為臨城等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

Java 內(nèi)存模型(JMM)

CPU 增加了緩存均衡了與內(nèi)存的速度差異,這一增加還是好幾層。

volatile和synchronized的區(qū)別是什么

此時內(nèi)存的短板不再那么明顯,CPU甚喜。但隨之卻帶來很多問題

volatile和synchronized的區(qū)別是什么

看上圖,每個核都有自己的一級緩存(L1 Cache),有的架構(gòu)里面還有所有核共用的二級緩存(L2 Cache)。使用緩存之后,當(dāng)線程要訪問共享變量時,如果 L1 中存在該共享變量,就不會再逐級訪問直至主內(nèi)存了。所以,通過這種方式,就補上了訪問內(nèi)存慢的短板

具體來說,線程讀/寫共享變量的步驟是這樣:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2.  從主內(nèi)存復(fù)制共享變量到自己的工作內(nèi)存

  3.  在工作內(nèi)存中對變量進行處理

  4.  處理完后,將變量值更新回主內(nèi)存

假設(shè)現(xiàn)在主內(nèi)存中有共享變量 X, 其初始值為 0

線程1先訪問變量 X, 套用上面的步驟就是這樣:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2.  L1 和 L2 中都沒有發(fā)現(xiàn)變量 X,直到在主內(nèi)存中找到

  3.  拷貝變量 X 到 L1 和 L2 中

  4.  在 L1 中將 X 的值修改為1,并逐層寫回到主內(nèi)存中

此時,在線程 1 眼中,X 的值是這樣的:

volatile和synchronized的區(qū)別是什么

接下來,線程 2 同樣按照上面的步驟訪問變量 X

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2.     L1 中沒有發(fā)現(xiàn)變量 X

  3.     L2 中發(fā)現(xiàn)了變量X

  4.     從L2中拷貝變量到L1中

  在L1中將X 的值修改為2,并逐層寫回到主內(nèi)存中

此時,線程 2 眼中,X 的值是這樣的:

volatile和synchronized的區(qū)別是什么

結(jié)合剛剛的兩次操作,當(dāng)線程1再訪問變量x,我們看看有什么問題:

volatile和synchronized的區(qū)別是什么

此刻,如果線程 1 再次將 x=1回寫,就會覆蓋線程2 x=2 的結(jié)果,同樣的共享變量,線程拿到的結(jié)果卻不一樣(線程1眼中x=1;線程2眼中x=2),這就是共享變量內(nèi)存不可見的問題。

怎么補坑呢?今天的兩位主角閃亮登場,不過在說明 volatile關(guān)鍵字之前,我們先來說說你最熟悉的 synchronized 關(guān)鍵字

synchronized

遇到線程不安全的問題,習(xí)慣性的會想到用 synchronized 關(guān)鍵字來解決問題,暫且先不論該辦法是否合理,我們來看 synchronized 關(guān)鍵字是怎么解決上面提到的共享變量內(nèi)存可見性問題的

  •  【進入】synchronized 塊的內(nèi)存語義是把在 synchronized 塊內(nèi)使用的變量從線程的工作內(nèi)存中清除,從主內(nèi)存中讀取

  •  【退出】synchronized 塊的內(nèi)存語義事把在 synchronized 塊內(nèi)對共享變量的修改刷新到主內(nèi)存中

二話不說,無情向下看 volatile

volatile

當(dāng)一個變量被聲明為 volatile 時:

  •  線程在【讀取】共享變量時,會先清空本地內(nèi)存變量值,再從主內(nèi)存獲取最新值

  •  線程在【寫入】共享變量時,不會把值緩存在寄存器或其他地方(就是剛剛說的所謂的「工作內(nèi)存」),而是會把值刷新回主內(nèi)存

有種換湯不換藥的感覺,你看的一點都沒錯

volatile和synchronized的區(qū)別是什么

所以,當(dāng)使用 synchronized 或 volatile 后,多線程操作共享變量的步驟就變成了這樣:

volatile和synchronized的區(qū)別是什么

簡單點來說就是不再參考 L1 和 L2 中共享變量的值,而是直接訪問主內(nèi)存

來點踏實的,上例子

public class ThreadNotSafeInteger {      /**       * 共享變量 value       */      private int value;      public int getValue() {          return value;      }      public void setValue(int value) {          this.value = value;      }  }

經(jīng)過前序分析鋪墊,很明顯,上面代碼中,共享變量 value 存在大大的隱患,嘗試對其作出一些改變

先使用 volatile 關(guān)鍵字改造:

public class ThreadSafeInteger {      /**       * 共享變量 value       */      private volatile int value;      public int getValue() {          return value;      }      public void setValue(int value) {          this.value = value;      }  }

再使用 synchronized 關(guān)鍵字改造

public class ThreadSafeInteger {      /**       * 共享變量 value       */      private int value;      public synchronized int getValue() {          return value;      }      public synchronized void setValue(int value) {          this.value = value;      }  }

這兩個結(jié)果是完全相同,在解決【當(dāng)前】共享變量數(shù)據(jù)可見性的問題上,二者算是等同的

如果說 synchronized 和 volatile 是完全等同的,那就沒必要設(shè)計兩個關(guān)鍵字了,繼續(xù)看個例子

@Slf4j  public class VisibilityIssue {      private static final int TOTAL = 10000;  //    即便像下面這樣加了 volatile 關(guān)鍵字修飾不會解決問題,因為并沒有解決原子性問題      private volatile int count;      public static void main(String[] args) {          VisibilityIssue visibilityIssue = new VisibilityIssue();          Thread thread1 = new Thread(() -> visibilityIssue.add10KCount());          Thread thread2 = new Thread(() -> visibilityIssue.add10KCount());          thread1.start();          thread2.start();          try {              thread1.join();              thread2.join();          } catch (InterruptedException e) {              log.error(e.getMessage());          }          log.info("count 值為:{}", visibilityIssue.count);      }      private void add10KCount(){          int start = 0;          while (start ++ < TOTAL){              this.count ++;          }      }  }

其實就是將上面setValue 簡單賦值操作 (this.value = value;)變成了 (this.count ++;)形式,如果你運行代碼,你會發(fā)現(xiàn),count的值始終是處于1w和2w之間的

將上面方法再以 synchronized 的形式做改動

@Slf4j  public class VisibilityIssue {      private static final int TOTAL = 10000;      private int count;       //... 同上      private synchronized void add10KCount(){          int start = 0;          while (start ++ < TOTAL){              this.count ++;          }      }  }

再次運行代碼,count 結(jié)果就是 2w

以上就是volatile和synchronized的區(qū)別是什么,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


分享標(biāo)題:volatile和synchronized的區(qū)別是什么
本文來源:http://weahome.cn/article/gocgos.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部