国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

重排序

2019-11-08 02:57:08
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

順序一致性

順序執(zhí)行性內(nèi)存模型: 是一個(gè)理論模型,人頭腦中認(rèn)為的正確的內(nèi)存模型。 順序一致性: 如果程序是正確同步的,程序的執(zhí)行將具有順序一致性;也可以說(shuō)成正確同步程序的執(zhí)行結(jié)果與順序一致性內(nèi)存模型的執(zhí)行結(jié)果相同。(同步是廣義的同步,包括同步原語(yǔ) synchronized、volatile、final 的正確使用)

重排序

優(yōu)勢(shì):編譯器和處理器為了優(yōu)化程序性能,可以對(duì)指令序列進(jìn)行重新排序。


重排序不影響單線程程序的執(zhí)行結(jié)果:因?yàn)橹嘏判虮仨氉袷財(cái)?shù)據(jù)依賴性,只有相互之間無(wú)依賴的的指令才可以重排序,而對(duì)無(wú)依賴的指令進(jìn)行重排序不影響單線程程序的執(zhí)行結(jié)果。

重排序會(huì)影響多線程程序的執(zhí)行結(jié)果,包括:

編譯期優(yōu)化的重排序:編譯器在不改變單線程程序語(yǔ)義的前提下,可以重新安排語(yǔ)句的執(zhí)行順序。指令級(jí)并行的重排序:如果不存在數(shù)據(jù)依賴性,處理器可以改變語(yǔ)句對(duì)應(yīng)的機(jī)器指令的執(zhí)行順序。

下面舉例說(shuō)明:

編譯期優(yōu)化的重排序

class RecorderExample{ int a = 0; boolean flag = false; public void write(){ a = 1; // 1 flag = true; // 2 } public void read(){ if(!flag){ a = 2; } }}

上述代碼中,假設(shè)線程A 首先執(zhí)行 write() 而線程B 后執(zhí)行 read(),則可能的時(shí)序?yàn)椋?/p>

這里寫圖片描述

最后得到結(jié)果為:

a = 2 flag = true

而由于重排序,1 和 2 可能會(huì)進(jìn)行互換,得到的時(shí)序?yàn)椋?/p>

這里寫圖片描述

最后得到結(jié)果為:

a = 1 flag = true

可以看到重排序?qū)е铝藘煞N不同的執(zhí)行結(jié)果;可以使用同步解決,如下:

class RecorderExample{ int a = 0; boolean flag = false; public synchronized void write(){ a = 1; flag = true; } public synchronized void read(){ if(!flag){ a = 2; } }}

同樣,假設(shè)線程A 首先執(zhí)行 write()和線程B 后執(zhí)行 read(),對(duì)比一下 JMM 中的執(zhí)行時(shí)序和順序一致性內(nèi)存模型中的執(zhí)行時(shí)序:

這里寫圖片描述

因?yàn)榧恿随i同步,所以同步塊內(nèi)的重排序并不影響多線程的執(zhí)行結(jié)果。

JMM的基本方針是在不改變正確同步程序的執(zhí)行結(jié)果的情況下,盡可能地利用重排序進(jìn)行性能優(yōu)化。因此同步塊內(nèi)臨界區(qū)的重排序是允許的。 針對(duì)未同步程序(包括單線程和多線程),順序一致性內(nèi)存模型能保證其順序一致性,JMM 不保證其順序一致性。

指令級(jí)并行的重排序

以雙重檢查鎖定為例:

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

對(duì)象的初始化可以分解為以下偽代碼:

memory = allocate();  // 1:分配對(duì)象的內(nèi)存空間ctorInstance(memory); // 2:初始化對(duì)象instance = memory; // 3:設(shè)置 instance 指向內(nèi)存空間

而編譯器很可能為了優(yōu)化程序的執(zhí)行效率進(jìn)行指令重排序,即對(duì) 2 和 3 進(jìn)行互換

memory = allocate();  // 1:分配對(duì)象的內(nèi)存空間instance = memory;   // 3:設(shè)置 instance 指向內(nèi)存空間 // 注意,此時(shí)對(duì)象還沒(méi)有被初始化!ctorInstance(memory); // 2:初始化對(duì)象

在進(jìn)行了上述重排序的情況下,可能造成下面的執(zhí)行順序:

這里寫圖片描述

上述過(guò)程中,線程B 訪問(wèn) instance 指向的對(duì)象的時(shí)候該對(duì)象尚未完成初始化,會(huì)引起各種幺蛾子的,請(qǐng)慎重。


解決辦法:很簡(jiǎn)單,使用 volatile 修飾 instance 變量即可;

private volatile static Singleton instance = null;

volatile 關(guān)鍵字通過(guò)提供內(nèi)存避障的方式禁止指令重排序。

單線程中會(huì)不會(huì)得到一個(gè)尚未完全初始化的對(duì)象呢?(不會(huì)) 因?yàn)?java 語(yǔ)言規(guī)范中 intra-thread semantics(線程內(nèi)語(yǔ)義)保證了重排序不會(huì)影響單線程程序的執(zhí)行結(jié)果。怎么理解呢?單線程中,也允許上述重排序,但是當(dāng)你使用 instance 引用的時(shí)候其指向的對(duì)象已經(jīng)初始化成功了。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 达孜县| 锡林浩特市| 达孜县| 会宁县| 汾西县| 长子县| 临漳县| 浮梁县| 新竹县| 汝州市| 永清县| 姜堰市| 海口市| 永泰县| 固镇县| 铜山县| 永嘉县| 凤阳县| 朔州市| 青河县| 东源县| 定南县| 兴城市| 金阳县| 康马县| 龙井市| 房产| 安溪县| 萨嘎县| 屏东县| 齐齐哈尔市| 乌兰县| 兰溪市| 永州市| 呈贡县| 柳江县| 张掖市| 临江市| 将乐县| 林芝县| 凤山市|