自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試官:有了解過指令重排嗎,什么是Happens-Before

開發(fā) 后端
指令重排可以保證串行語義一致,但是沒有義務(wù)保證多線程間的語義也一致**。所以在多線程下,指令重排序可能會(huì)導(dǎo)致一些問題。


重排序

首先,什么是重排序?計(jì)算機(jī)在執(zhí)行過程中,為了提高性能,會(huì)對(duì)編譯器和編譯器做指令重排。

這么做為啥可以提高性能呢?

我們知道計(jì)算機(jī)在執(zhí)行的時(shí)候都是一個(gè)個(gè)指令去執(zhí)行,不同的指令可能操作的硬件不一樣,在執(zhí)行的過程中可能會(huì)產(chǎn)生中斷,打個(gè)比方,兩個(gè)指令a和b他們操作的東西各不相同,如果加載a的時(shí)候停頓了,b就加載不到,但是實(shí)際上它們互補(bǔ)影響,我也可以先加載b在加載a,所以指令重排是減少停頓的一種方法,這樣大大提高了效率。

指令重排的方式

指令重排一般分為以下三種:

  • 編譯器優(yōu)化重新安排語句的執(zhí)行順序。
  • 指令并行重排利用指令級(jí)并行技術(shù)將多個(gè)指令并行執(zhí)行,如果指令之前沒有數(shù)據(jù)依賴,處理器可以改變對(duì)應(yīng)機(jī)器指令的執(zhí)行順序。
  • 內(nèi)存系統(tǒng)重排由于處理使用緩存和讀寫緩沖區(qū),所以它們是亂序的。

指令重排可以保證串行語義一致,但是沒有義務(wù)保證多線程間的語義也一致**。所以在多線程下,指令重排序可能會(huì)導(dǎo)致一些問題。

順序一致性模型

順序一致性模型是一個(gè)「理論參考模型」,內(nèi)存模型在設(shè)計(jì)的時(shí)候都會(huì)以順序一致性內(nèi)存模型作為參考。

數(shù)據(jù)競(jìng)爭(zhēng)

我們知道在多線程情況下,同時(shí)讀寫一個(gè)變量會(huì)導(dǎo)致結(jié)果的不確定性,這就存在了數(shù)據(jù)競(jìng)爭(zhēng),相反的如果線程在同步情況下,就不存在數(shù)據(jù)競(jìng)爭(zhēng)。

JMM對(duì)于同步的多線程情況下,程序執(zhí)行可以保證順序一致性,同步包括了使用volatile、final、synchronized等關(guān)鍵字來實(shí)現(xiàn)「多線程下的同步」,這里的前提正確使用它們,如果使用不當(dāng),就不能保證

什么是順序一致性模型

我們?cè)谏瞎?jié)給大家講了Java的內(nèi)存模型,提到了內(nèi)存可見性的概念,順序一致性模型它的最終目的就是保證內(nèi)存的可見性。

它主要有兩大特性:

  • 一個(gè)線程中的所有操作必須按照程序的順序(代碼順序)來執(zhí)行。
  • 不管線程是否同步,所有線程保持單一的執(zhí)行順序并且可見,且是原子性

JMM中同步的順序一致性

在JMM中,臨界區(qū)(同步方法或同步塊)的代碼可以發(fā)生重排,但對(duì)其它線程是無感知的,這樣既提高了執(zhí)行效率又不影響最終結(jié)果

JMM中未同步的順序一致性

  • JMM沒有保證未同步程序的執(zhí)行結(jié)果與該程序在順序一致性中執(zhí)行結(jié)果一致。
  • JMM不保證單線程內(nèi)的操作會(huì)按程序的順序執(zhí)行(因?yàn)橹噶钪嘏?。
  • JMM不保證所有線程能看到一致的操作執(zhí)行順序(因?yàn)椴荒鼙WC所以操作立即可見)。
  • JMM不保證對(duì)64位的long型和double型變量的寫操作具有原子性。

什么是happens-before

JMM提供了「happens-before規(guī)則」(JSR-133規(guī)范), 開發(fā)者可以遵循這種規(guī)范編寫程序,可以保證程序在JMM中具有強(qiáng)的內(nèi)存可見性。JMM使用happens-before的概念來定制兩個(gè)操作之間的執(zhí)行順序。這兩個(gè)操作可以在一個(gè)線程以內(nèi),也可以是不同的線程之間。因此,JMM可以通過happens-before關(guān)系向程序員提供跨線程的內(nèi)存可見性保證。

happens-before關(guān)系的定義如下:

  1. 如果一個(gè)操作happens-before另一個(gè)操作,那么第一個(gè)操作的執(zhí)行結(jié)果將對(duì)第二個(gè)操作可見,而且第一個(gè)操作的執(zhí)行順序排在第二個(gè)操作之前。
  2. 「兩個(gè)操作之間存在happens-before關(guān)系,并不意味著Java平臺(tái)的具體實(shí)現(xiàn)必須要按照happens-before關(guān)系指定的順序來執(zhí)行。如果重排序之后的執(zhí)行結(jié)果,與按happens-before關(guān)系來執(zhí)行的結(jié)果一致,那么JMM也允許這樣的重排序。」

總之,「如果操作A happens-before操作B,那么操作A在內(nèi)存上所做的操作對(duì)操作B都是可見的,不管它們?cè)诓辉谝粋€(gè)線程?!?/p>

在Java中,有以下天然的happens-before關(guān)系:

  • 程序順序規(guī)則:一個(gè)線程中的每一個(gè)操作,happens-before于該線程中的任意后續(xù)操作。
  • 監(jiān)視器鎖規(guī)則:對(duì)一個(gè)鎖的解鎖,happens-before于隨后對(duì)這個(gè)鎖的加鎖。
  • volatile變量規(guī)則:對(duì)一個(gè)volatile域的寫,happens-before于任意后續(xù)對(duì)這個(gè)volatile域的讀。
  • 傳遞性:如果A happens-before B,且B happens-before C,那么A happens-before C。
  • start規(guī)則:ThreadA start happens-before ThreadB start
  • join規(guī)則:如果線程A執(zhí)行操作ThreadB.join()并成功返回,那么線程B中的任意操作happens-before于線程A從ThreadB.join()操作成功返回。

結(jié)束語

本節(jié)內(nèi)容可能不像之前那么好理解,比較抽象,所以本文也有不足的地方,大家自己可以多查查一些資料,綜合理解。下一節(jié),帶大家深入學(xué)習(xí)一下Java的volatile。

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2020-05-28 07:50:18

重排序happens-befCPU

2022-07-26 08:40:42

Java并發(fā)工具類

2022-08-02 06:31:32

Java并發(fā)工具類

2022-07-11 10:47:46

容器JAVA

2022-06-10 13:56:42

Java

2022-06-30 08:14:05

Java阻塞隊(duì)列

2022-06-27 08:01:45

Java內(nèi)存模型

2022-06-24 06:43:57

線程池線程復(fù)用

2022-06-15 15:14:17

Java公平鎖非公平鎖

2022-06-09 11:20:44

volatile關(guān)鍵字

2022-06-30 14:31:57

Java阻塞隊(duì)列

2024-09-09 08:30:56

代碼

2021-05-09 18:32:05

JMMHappens-befJava

2022-07-18 14:18:26

Babel代碼面試

2021-09-07 10:44:33

Java 注解開發(fā)

2021-04-12 21:34:29

Redis故障數(shù)據(jù)

2021-12-08 06:53:29

面試動(dòng)態(tài)代理

2024-02-22 15:36:23

Java內(nèi)存模型線程

2022-09-29 07:30:57

數(shù)據(jù)庫索引字段

2024-04-15 00:01:00

STWJava垃圾
點(diǎn)贊
收藏

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