亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一文精通Java中的volatile關(guān)鍵字

 更新時(shí)間:2019年05月07日 09:39:14   作者:架構(gòu)與我  
volatile是java中的關(guān)鍵詞之一,這篇文章主要給大家介紹了關(guān)于Java中volatile關(guān)鍵字的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

在一些開源的框架的源碼當(dāng)中時(shí)不時(shí)都可以看到volatile這個(gè)關(guān)鍵字,最近特意學(xué)習(xí)一下volatile關(guān)鍵字的使用方法。

volatile 關(guān)鍵字:當(dāng)多個(gè)線程進(jìn)行操作共享數(shù)據(jù)時(shí),可以保證內(nèi)存中的數(shù)據(jù)可見。 相較于 synchronized 是一種較為輕量級(jí)的同步策略。

缺點(diǎn):

1. volatile 不具備“互斥性”

2. volatile 不能保證變量的“原子性”

很多資料中是這樣介紹volatile關(guān)鍵字的:

volatile是輕量級(jí)的synchronized,它在多處理器開發(fā)中保證了共享變量的“可見性”??梢娦缘囊馑际钱?dāng)一個(gè)線程修改一個(gè)共享變量時(shí),另外一個(gè)線程能讀到這個(gè)修改的值。

文字不太好理解,通過(guò)例子來(lái)理解。

1、例子

首先看一個(gè)沒有使用volatile關(guān)鍵字例子:

package com.swnote.java;

/**
 * volatile測(cè)試?yán)?
 *
 * @author lzj
 * @date [2019-04-47]
 */
public class VolatileTest {

 private boolean flag;

 public static void main(String[] args) {
 VolatileTest test = new VolatileTest();
 test.test();
 }

 public void test() {
 new Thread(() -> {
  try {
  Thread.sleep(1000L);
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  flag = true;
 }).start();

 new Thread(() -> {
  while (true) {
  if (flag) {
   System.out.println("thread flag = " + flag);
  }
  }
 }).start();
 }
}

該例子中定義了一個(gè)flag共享變量,test方法里面開啟了兩個(gè)線程,第一個(gè)線程在等待1秒中后修改共享變量flag的值為true,第二個(gè)線程通過(guò)循環(huán)判斷flag的值,當(dāng)flag的值為true時(shí),輸出內(nèi)容。

此時(shí)有兩種猜想:

  • 執(zhí)行后,可以看到輸出內(nèi)容,即說(shuō)明第二個(gè)線程能夠感知到第一個(gè)線程對(duì)共享變量flag的修改
  • 執(zhí)行后,沒有任務(wù)內(nèi)容,即說(shuō)明第二個(gè)線程無(wú)法感知到第一個(gè)線程對(duì)共享變量flag的修改

然后執(zhí)行結(jié)果為:

沒有任務(wù)的輸出內(nèi)容,即證明了此時(shí)這樣情況下第二個(gè)線程無(wú)法感知到第一個(gè)線程對(duì)共享變量flag的修改的

現(xiàn)在修改一下例子,即為flag變量加上volatile關(guān)鍵字,即:

private volatile boolean flag;

然后再運(yùn)行,此時(shí)結(jié)果為:

此時(shí)就有內(nèi)容輸出了,說(shuō)明加上volatile關(guān)鍵字后,第二個(gè)線程可以感知到第一個(gè)線程對(duì)共享變量flag的修改的,這就是上面概念中所說(shuō)的volatile在多處理器開發(fā)中保證了共享變量的“可見性”。

2、原理

通過(guò)上面的例子證明了volatile在多處理器開發(fā)中保證了共享變量的“可見性”,那它是怎么實(shí)現(xiàn)的呢?

這時(shí)就得介紹一下Java的內(nèi)存模型了,首先看如下示意圖:

Java內(nèi)存模型是如上面所示的:

共享變量存儲(chǔ)在主內(nèi)存中,每個(gè)線程都有一個(gè)私有的本地內(nèi)存,本地內(nèi)存保存了被該線程使用到的主內(nèi)存的副本拷貝,線程對(duì)變量的所有操作都必須在自己的本地內(nèi)存中進(jìn)行,而不能直接讀寫主內(nèi)存中的變量。

根據(jù)此理解,上述例子的在沒有加volatile時(shí)的情況是這樣的:

第一個(gè)線程從主內(nèi)存中獲取共享變量flag的值,此時(shí)值為false,將該值放到自己的本地內(nèi)存中,然后對(duì)變量進(jìn)行修改,將值改為true,此時(shí)也只是將本地內(nèi)存中flag的值改為了true,此時(shí)還沒有將值同步到主內(nèi)存中,然后第二線程也是將共享變量flag的值放到自己的本地內(nèi)存中,而此時(shí)flag的值還是為false,所以就是一直沒有內(nèi)容輸出了。

然而加上volatile關(guān)鍵字后,第一個(gè)線程對(duì)flag的修改會(huì)強(qiáng)制刷新到主內(nèi)存中去,同時(shí)還會(huì)導(dǎo)致其他線程中的本地內(nèi)存的值會(huì)無(wú)效,需要重新到主內(nèi)存獲取,這樣就保證了第一個(gè)線程對(duì)flag修改后,第二線程能夠感知到。

3、注意點(diǎn)

volatile是輕量級(jí)的synchronized,但是它是不能夠代替synchronized的,因?yàn)関olatile只能保證原子性操作的安全,對(duì)于復(fù)合操作,volatile是不能保證線程安全的。

例如:

package com.swnote.java;

/**
 * 復(fù)合操作例子
 *
 * @author lzj
 * @date [2019-04-27]
 */
public class StatisticTest {
 private volatile int num = 0;

 public static void main(String[] args) {
  StatisticTest test = new StatisticTest();
  test.statistic();
 }

 public void statistic() {
  for (int i = 0; i < 20; i++) {
   new Thread(() -> {
    num++;
   }).start();
  }

  System.out.println("num = " + num);
 }
}

期望的運(yùn)行結(jié)果是20,可是幾乎每次運(yùn)行結(jié)果都是不一樣的,例如有的結(jié)果為:

這是因?yàn)閚um++這個(gè)操作不是原子性的,所以即使使用了volatile關(guān)鍵字,也是不能保證安全的。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

最新評(píng)論