国产探花免费观看_亚洲丰满少妇自慰呻吟_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ā)表
主站蜘蛛池模板: 淅川县| 渭源县| 江达县| 邵武市| 新泰市| 若羌县| 靖西县| 沙湾县| 隆化县| 都昌县| 庆安县| 靖边县| 寿宁县| 工布江达县| 黎城县| 锦屏县| 潜江市| 平乐县| 盐边县| 孟州市| 洪雅县| 公安县| 金门县| 太保市| 松滋市| 五峰| 于田县| 苏尼特左旗| 原阳县| 石林| 高清| 吉木乃县| 盱眙县| 嘉祥县| 新邵县| 桦川县| 嘉鱼县| 岫岩| 西乌珠穆沁旗| 泽普县| 华阴市|