<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文讀懂 volatile 關(guān)鍵字

          共 4888字,需瀏覽 10分鐘

           ·

          2020-07-28 22:55

          作者:對弈
          來源:https://www.cnblogs.com/MessiXiaoMo3334/p/12615823.html

          volatile是Java虛擬機(jī)提供的輕量級(jí)的同步機(jī)制(“乞丐版”的synchronized)

          1. 保證可見性
          2. 不保證原子性
          3. 禁止指令重排

          可見性

          指當(dāng)多個(gè)線程訪問同一個(gè)變量時(shí),如果其中一個(gè)線程修改了這個(gè)變量的值,其他線程能夠立即看得到修改的值

          驗(yàn)證可見性demo:

          import java.util.concurrent.TimeUnit;

          class MyData {
          volatile int number = 0;
          public void addTo60() {
          number = 60;
          }
          }
          public class VolatileDemo {
          public static void main() {
          MyData myData = new MyData();
          new Thread(() -> {
          System.out.println(Thread.currentThread().getName() + "\t come in");
          try {
          TimeUnit.SECONDS.sleep(3);
          } catch (InterruptedException e) {
          e.printStackTrace();
          }
          myData.addTo60();
          System.out.println(Thread.currentThread().getName() + "\t updated number: " + myData.number);
          }, "AAA").start();
          while (myData.number == 0) {}
          System.out.println(Thread.currentThread().getName() + "\t mission is over");
          }
          }

          結(jié)果:

          AAA  come in
          main mission is over
          AAA updated number: 60

          不保證原子性

          原子性:程序中的所有操作是不可中斷的,要么全部執(zhí)行成功要么全部執(zhí)行失敗

          不保證原子性正是volatile輕量級(jí)的體現(xiàn),多個(gè)線程對volatile修飾的變量進(jìn)行操作時(shí),會(huì)出現(xiàn)容易出現(xiàn)寫覆蓋的情況(i++)

          驗(yàn)證不保證原子性demo:

          import java.util.concurrent.TimeUnit;
          import java.util.concurrent.atomic.AtomicInteger;

          class MyData {
          volatile int number = 0;
          public void addPlusPlus() {
          number++;
          }
          }
          public class VolatileDemo {
          public static void main(String[] args) {
          MyData myData = new MyData();
          for (int i = 0; i < 20; i++) {
          new Thread(() -> {
          for (int j = 0; j < 1000; j++) {
          myData.addPlusPlus();
          }
          }, String.valueOf(i)).start();
          }
          while (Thread.activeCount() > 2) {
          Thread.yield();
          }
          System.out.println(Thread.currentThread().getName() + "\t finally number value: " + myData.number);
          }
          }

          結(jié)果:

          main    finally number value: 19109

          解決不保證原子性問題:Atomic

          import java.util.concurrent.TimeUnit;
          import java.util.concurrent.atomic.AtomicInteger;

          class MyData {
          volatile int number = 0;
          public void addPlusPlus() {
          number++;
          }

          AtomicInteger atomicInteger = new AtomicInteger();
          public void addAtmic() {
          atomicInteger.getAndIncrement();
          }
          }
          public class VolatileDemo {
          public static void main(String[] args) {
          MyData myData = new MyData();
          for (int i = 0; i < 20; i++) {
          new Thread(() -> {
          for (int j = 0; j < 1000; j++) {
          myData.addAtmic();
          }
          }, String.valueOf(i)).start();
          }
          while (Thread.activeCount() > 2) {
          Thread.yield();
          }
          System.out.println(Thread.currentThread().getName() + "\t finally number value: " + myData.number);
          System.out.println(Thread.currentThread().getName() + "\t AtomicInteger type,finally number value: "
          + myData.atomicInteger);
          }
          }

          結(jié)果:

          main     finally number value: 19746
          main AtomicInteger type,finally number value: 20000

          禁止指令重排

          指令重排:為了提高程序運(yùn)行效率,編譯器可能會(huì)對輸入指令進(jìn)行重新排序,即程序中各個(gè)語句的執(zhí)行先后順序同代碼中的順序不一定一致。(但是它會(huì)保證單線程程序最終執(zhí)行結(jié)果和代碼順序執(zhí)行的結(jié)果是一致的,它忽略了數(shù)據(jù)的依賴性

          源代碼 -> 編譯器優(yōu)化重排 -> 指令并行重排 -> 內(nèi)存系統(tǒng)重排 -> 最終執(zhí)行指令

          volatile能夠?qū)崿F(xiàn)禁止指令重排的底層原理:

          • 內(nèi)存屏障(Memory Barrier):它是一個(gè)CPU指令。由于編譯器和CPU都能夠執(zhí)行指令重排,如果在指令間插入一條Memory Barrier則會(huì)告訴編譯器和CPU,任何指令都不能和該條Memory Barrier指令進(jìn)行重排序,即通過插入內(nèi)存屏障指令能夠禁止在內(nèi)存屏障前后的指令執(zhí)行重排序 優(yōu)化
          • 內(nèi)存屏障的另外一個(gè)作用是強(qiáng)制刷新各種CPU的緩存數(shù)據(jù),因此任何CPU上的線程都能夠讀取到這些數(shù)據(jù)的最新版本。以上兩點(diǎn)正好對應(yīng)了volatile關(guān)鍵字的禁止指令重排序和內(nèi)存可見性的特點(diǎn)
          • 對volatile變量進(jìn)行寫操作時(shí),會(huì)在寫操作之后加入一條store屏障指令,將工作內(nèi)存中的共享變量copy刷新回主內(nèi)存中;對volatile變量進(jìn)行讀操作時(shí),會(huì)在讀操作之前加入一條load的屏障指令,從主內(nèi)存中讀取共享變量

          應(yīng)用場景:

          • 高并發(fā)環(huán)境下DCL單例模式使用volatile
          public class SingletonDemo {
          private static volatile SingletonDemo instance = null;
          private SingletonDemo() {
          System.out.println(Thread.currentThread().getName() + "我是構(gòu)造方法SingletonDemo()");
          }
          public static SingletonDemo getInstance() {
          if (instance == null) {
          synchronized (SingletonDemo.class) {
          if (instance == null) {
          instance = new SingletonDemo();
          }
          }
          }
          return instance;
          }
          public static void main(String[] args) {
          for (int i = 0; i < 10; i++) {
          new Thread(() -> {
          SingletonDemo.getInstance();
          }, String.valueOf(i)).start();
          }
          }
          }
          • JUC包下AtomicXxx類:原子類AtomicXxx中都有一個(gè)成員變量value,該value變量被聲明為volatile,保證 AtomicXxx類的內(nèi)存可見性,而原子性由CAS算法&Unsafe類保證,結(jié)合這兩點(diǎn)才能讓AtomicXxx類很好地替代synchronized關(guān)鍵字。
          public class AtomicInteger extends Number implements java.io.Serializable {
          // ...
          private volatile int value;
          // ...
          }

          最后免費(fèi)給大家分享50個(gè)Java項(xiàng)目實(shí)戰(zhàn)資料,涵蓋入門、進(jìn)階各個(gè)階段學(xué)習(xí)內(nèi)容,可以說非常全面了。大部分視頻還附帶源碼,學(xué)起來還不費(fèi)勁!


          附上截圖。(下面有下載方式)。


          項(xiàng)目領(lǐng)取方式:

          掃描下方公眾號(hào)回復(fù):50

          可獲取下載鏈接

          ???

          ?長按上方二維碼?2 秒
          回復(fù)「50」即可獲取資料


          點(diǎn)贊是最大的支持?

          瀏覽 71
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产肏屄青青肏屄视频 | 日韩动态| 91AV在线视频播放 | 伊人久久成人 | 欧美se在线 |