成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試突擊:Volatile 有什么用?

開發(fā) 前端
volatile 是 Java 并發(fā)編程的重要組成部分,它的主要作用有兩個:保證內(nèi)存的可見性和禁止指令重排序。

volatile 是 Java 并發(fā)編程的重要組成部分,也是常見的面試題之一,它的主要作用有兩個:保證內(nèi)存的可見性和禁止指令重排序。下面我們具體來看這兩個功能。

內(nèi)存可見性

說到內(nèi)存可見性問題就不得不提 Java 內(nèi)存模型,Java 內(nèi)存模型(Java Memory Model)簡稱為 JMM,主要是用來屏蔽不同硬件和操作系統(tǒng)的內(nèi)存訪問差異的,因?yàn)樵诓煌挠布筒煌牟僮飨到y(tǒng)下,內(nèi)存的訪問是有一定的差異得,這種差異會導(dǎo)致相同的代碼在不同的硬件和不同的操作系統(tǒng)下有著不一樣的行為,而 Java 內(nèi)存模型就是解決這個差異,統(tǒng)一相同代碼在不同硬件和不同操作系統(tǒng)下的差異的。

Java 內(nèi)存模型規(guī)定:所有的變量(實(shí)例變量和靜態(tài)變量)都必須存儲在主內(nèi)存中,每個線程也會有自己的工作內(nèi)存,線程的工作內(nèi)存保存了該線程用到的變量和主內(nèi)存的副本拷貝,線程對變量的操作都在工作內(nèi)存中進(jìn)行。線程不能直接讀寫主內(nèi)存中的變量,如下圖所示:

然而,Java 內(nèi)存模型會帶來一個新的問題,那就是內(nèi)存可見性問題,也就是當(dāng)某個線程修改了主內(nèi)存中共享變量的值之后,其他線程不能感知到此值被修改了,它會一直使用自己工作內(nèi)存中的“舊值”,這樣程序的執(zhí)行結(jié)果就不符合我們的預(yù)期了,這就是內(nèi)存可見性問題,我們用以下代碼來演示一下這個問題:

private static boolean flag = false;
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while (!flag) {

}
System.out.println("終止執(zhí)行");
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("設(shè)置 flag=true");
flag = true;
}
});
t2.start();
}

以上代碼我們預(yù)期的結(jié)果是,在線程 1 執(zhí)行了 1s 之后,線程 2 將 flag 變量修改為 true,之后線程 1 終止執(zhí)行,然而,因?yàn)榫€程 1 感知不到 flag 變量發(fā)生了修改,也就是內(nèi)存可見性問題,所以會導(dǎo)致線程 1 會永遠(yuǎn)的執(zhí)行下去,最終我們看到的結(jié)果是這樣的:

如何解決以上問題呢?只需要給變量 flag 加上 volatile 修飾即可,具體的實(shí)現(xiàn)代碼如下:

private volatile static boolean flag = false;
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while (!flag) {

}
System.out.println("終止執(zhí)行");
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("設(shè)置 flag=true");
flag = true;
}
});
t2.start();
}

以上程序的執(zhí)行結(jié)果如下圖所示:

禁止指令重排序

指令重排序是指編譯器或 CPU 為了優(yōu)化程序的執(zhí)行性能,而對指令進(jìn)行重新排序的一種手段。

指令重排序的實(shí)現(xiàn)初衷是好的,但是在多線程執(zhí)行中,如果執(zhí)行了指令重排序可能會導(dǎo)致程序執(zhí)行出錯。指令重排序最典型的一個問題就發(fā)生在單例模式中,比如以下問題代碼:

public class Singleton {
private Singleton() {}
private static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) { //
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); //
}
}
}
return instance;
}
}

以上問題發(fā)生在代碼 ② 這一行“instance = new Singleton();”,這行代碼看似只是一個創(chuàng)建對象的過程,然而它的實(shí)際執(zhí)行卻分為以下 3 步:

  • 創(chuàng)建內(nèi)存空間。
  • 在內(nèi)存空間中初始化對象 Singleton。
  • 將內(nèi)存地址賦值給 instance 對象(執(zhí)行了此步驟,instance 就不等于 null 了)。

如果此變量不加 volatile,那么線程 1 在執(zhí)行到上述代碼的第 ② 處時就可能會執(zhí)行指令重排序,將原本是 1、2、3 的執(zhí)行順序,重排為 1、3、2。但是特殊情況下,線程 1 在執(zhí)行完第 3 步之后,如果來了線程 2 執(zhí)行到上述代碼的第 ① 處,判斷 instance 對象已經(jīng)不為 null,但此時線程 1 還未將對象實(shí)例化完,那么線程 2 將會得到一個被實(shí)例化“一半”的對象,從而導(dǎo)致程序執(zhí)行出錯,這就是為什么要給私有變量添加 volatile 的原因了。

要使以上單例模式變?yōu)榫€程安全的程序,需要給 instance 變量添加 volatile 修飾,它的最終實(shí)現(xiàn)代碼如下:

public class Singleton {
private Singleton() {}
// 使用 volatile 禁止指令重排序
private static volatile Singleton instance = null; // 【主要是此行代碼發(fā)生了變化】
public static Singleton getInstance() {
if (instance == null) { //
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); //
}
}
}
return instance;
}
}

總結(jié)

volatile 是 Java 并發(fā)編程的重要組成部分,它的主要作用有兩個:保證內(nèi)存的可見性和禁止指令重排序。volatile 常使用在一寫多讀的場景中,比如 CopyOnWriteArrayList 集合,它在操作的時候會把全部數(shù)據(jù)復(fù)制出來對寫操作加鎖,修改完之后再使用 setArray 方法把此數(shù)組賦值為更新后的值,使用 volatile 可以使讀線程很快的告知到數(shù)組被修改,不會進(jìn)行指令重排,操作完成后就可以對其他線程可見了。

責(zé)任編輯:武曉燕 來源: Java面試真題解析
相關(guān)推薦

2022-05-30 07:34:33

三范式Java

2022-07-13 07:06:47

HTTPSHTTP協(xié)議

2022-07-29 08:25:02

volatileC語言原子

2022-05-26 09:24:09

volatile懶漢模式

2022-08-22 07:06:32

MyBatisSQL占位符

2022-08-03 07:04:56

GETHTTPPOST

2022-04-26 08:02:00

locktryLocklockInterr

2022-08-10 07:06:57

IoCDISpring

2022-04-24 07:59:53

synchronizJVMAPI

2022-02-08 07:02:32

進(jìn)程線程操作系統(tǒng)

2022-08-15 07:06:50

Propertiesyml配置

2022-04-11 07:40:45

synchroniz靜態(tài)方法程序

2024-01-25 10:23:22

對象存儲存儲數(shù)據(jù)

2024-08-28 11:58:02

2023-03-26 21:51:42

2020-04-23 14:09:13

URI挖坑前端

2022-06-06 07:35:26

MySQLInnoDBMyISAM

2009-06-17 15:51:55

java有什么用

2017-11-22 15:50:58

Netty微服務(wù)RPC

2017-09-19 15:22:44

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产乱人伦精品一区二区 | 一区二区三区国产 | 亚洲精品免费视频 | 久久高清| 国产日韩欧美在线 | 国产一区二区在线91 | 久久精品国产亚洲a | 成人在线亚洲 | 亚洲国产网站 | 国产第一页在线观看 | 91色视频在线观看 | 99这里只有精品视频 | 免费的色网站 | 久久一二| 最新高清无码专区 | jav成人av免费播放 | 欧美一区二区三区,视频 | 在线日韩视频 | 欧美国产精品一区二区三区 | 成人亚洲视频 | 精品国产18久久久久久二百 | 日韩国产一区二区三区 | a级黄色片在线观看 | 精品国产乱码久久久久久图片 | 91在线观 | 阿v视频在线观看 | 亚洲精彩免费视频 | 欧美一区二区视频 | 亚洲精品中文字幕在线观看 | 亚洲欧美中文字幕在线观看 | 国产精品日日做人人爱 | 国产精品久久久久久一区二区三区 | 久色视频在线观看 | 国产一区二区三区四区 | 免费观看视频www | 亚洲国产精品91 | 黄色网址在线免费观看 | 日本久久久一区二区三区 | 日韩at| 精品久久久久久久 | 国产激情一区二区三区 |