深入理解Java內(nèi)存模型——final

1. final的簡(jiǎn)介

final可以修飾變量,方法和類,用于表示所修飾的內(nèi)容一旦賦值之后就不會(huì)再被改變屋确,比如String類就是一個(gè)final類型的類。即使能夠知道final具體的使用方法续扔,我想對(duì)final在多線程中存在的重排序問題也很容易忽略攻臀,希望能夠一起做下探討。

2. final的具體使用場(chǎng)景

final能夠修飾變量纱昧,方法和類刨啸,也就是final使用范圍基本涵蓋了java每個(gè)地方,下面就分別以鎖修飾的位置:變量识脆,方法和類分別來說一說设联。

2.1 變量

在java中變量,可以分為成員變量以及方法局部變量灼捂。因此也是按照這種方式依次來說离例,以避免漏掉任何一個(gè)死角。

2.1.1 final成員變量

通常每個(gè)類中的成員變量可以分為類變量(static修飾的變量)以及實(shí)例變量悉稠。針對(duì)這兩種類型的變量賦初值的時(shí)機(jī)是不同的宫蛆,類變量可以在聲明變量的時(shí)候直接賦初值或者在靜態(tài)代碼塊中給類變量賦初值。而實(shí)例變量可以在聲明變量的時(shí)候給實(shí)例變量賦初值的猛,在非靜態(tài)初始化塊中以及構(gòu)造器中賦初值耀盗。

類變量有兩個(gè)時(shí)機(jī)賦初值,而實(shí)例變量則可以有三個(gè)時(shí)機(jī)賦初值卦尊。當(dāng)final變量未初始化時(shí)系統(tǒng)不會(huì)進(jìn)行隱式初始化袍冷,會(huì)出現(xiàn)報(bào)錯(cuò)。這樣說起來還是比較抽象猫牡,下面用具體的代碼來演示胡诗。(代碼涵蓋了final修飾變量所有的可能情況,耐心看下去會(huì)有收獲的:) )

image

看上面的圖片已經(jīng)將每種情況整理出來了淌友,這里用截圖的方式也是覺得在IDE出現(xiàn)紅色出錯(cuò)的標(biāo)記更能清晰的說明情況』突郑現(xiàn)在我們來將這幾種情況歸納整理一下:

類變量:必須要在靜態(tài)初始化塊中指定初始值或者聲明該類變量時(shí)指定初始值,而且只能在這兩個(gè)地方之一進(jìn)行指定震庭;

實(shí)例變量:必要要在非靜態(tài)初始化塊瑰抵,聲明該實(shí)例變量或者在構(gòu)造器中指定初始值,而且只能在這三個(gè)地方進(jìn)行指定器联。

2.2.2 final局部變量

final局部變量由程序員進(jìn)行顯式初始化二汛,如果final局部變量已經(jīng)進(jìn)行了初始化則后面就不能再次進(jìn)行更改婿崭,如果final變量未進(jìn)行初始化,可以進(jìn)行賦值肴颊,當(dāng)且僅有一次賦值氓栈,一旦賦值之后再次賦值就會(huì)出錯(cuò)。下面用具體的代碼演示final局部變量的情況:

image

現(xiàn)在我們來換一個(gè)角度進(jìn)行考慮婿着,final修飾的是基本數(shù)據(jù)類型和引用類型有區(qū)別嗎授瘦?

final基本數(shù)據(jù)類型 VS final引用數(shù)據(jù)類型

通過上面的例子我們已經(jīng)看出來,如果final修飾的是一個(gè)基本數(shù)據(jù)類型的數(shù)據(jù)竟宋,一旦賦值后就不能再次更改提完,那么,如果final是引用數(shù)據(jù)類型了丘侠?這個(gè)引用的對(duì)象能夠改變嗎徒欣?我們同樣來看一段代碼。

public class FinalExample {
   //在聲明final實(shí)例成員變量時(shí)進(jìn)行賦值
   private final static Person person = new Person(24, 170);
   public static void main(String[] args) {
       //對(duì)final引用數(shù)據(jù)類型person進(jìn)行更改
       person.age = 22;
       System.out.println(person.toString());
   }   static class Person {
       private int age;
       private int height;
       public Person(int age, int height) {
           this.age = age;
           this.height = height;
       }       
      @Override
       public String toString() { 
          return "Person{" + 
                  "age=" + age + 
                  ", height=" + height + 
                  '}';
       }
   }
}

當(dāng)我們對(duì)final修飾的引用數(shù)據(jù)類型變量person的屬性改成22蜗字,是可以成功操作的打肝。通過這個(gè)實(shí)驗(yàn)我們就可以看出來當(dāng)final修飾基本數(shù)據(jù)類型變量時(shí),不能對(duì)基本數(shù)據(jù)類型變量重新賦值秽澳,因此基本數(shù)據(jù)類型變量不能被改變。

而對(duì)于引用類型變量而言戏羽,它僅僅保存的是一個(gè)引用担神,final只保證這個(gè)引用類型變量所引用的地址不會(huì)發(fā)生改變,即一直引用這個(gè)對(duì)象始花,但這個(gè)對(duì)象屬性是可以改變的妄讯。

宏變量

利用final變量的不可更改性,在滿足一下三個(gè)條件時(shí)酷宵,該變量就會(huì)成為一個(gè)“宏變量”亥贸,即是一個(gè)常量。

  • 使用final修飾符修飾浇垦;

  • 在定義該final變量時(shí)就指定了初始值炕置;

  • 該初始值在編譯時(shí)就能夠唯一指定。

注意:當(dāng)程序中其他地方使用該宏變量的地方男韧,編譯器會(huì)直接替換成該變量的值

2.2 方法

重寫朴摊?

當(dāng)父類的方法被final修飾的時(shí)候,子類不能重寫父類的該方法此虑,比如在Object中甚纲,getClass()方法就是final的,我們就不能重寫該方法朦前,但是hashCode()方法就不是被final所修飾的介杆,我們就可以重寫hashCode()方法鹃操。我們還是來寫一個(gè)例子來加深一下理解:

先定義一個(gè)父類,里面有final修飾的方法test();

public class FinalExampleParent {   public final void test() {   }}

然后FinalExample繼承該父類春哨,當(dāng)重寫test()方法時(shí)出現(xiàn)報(bào)錯(cuò)荆隘,如下圖:

image

通過這個(gè)現(xiàn)象我們就可以看出來被final修飾的方法不能夠被子類所重寫。

重載悲靴?

public class FinalExampleParent {   public final void test() {   }   public final void test(String str) {   }}

可以看出被final修飾的方法是可以重載的臭胜。經(jīng)過我們的分析可以得出如下結(jié)論:

1. 父類的final方法是不能夠被子類重寫的

2. final方法是可以被重載的

2.3 類

當(dāng)一個(gè)類被final修飾時(shí),表名該類是不能被子類繼承的癞尚。子類繼承往往可以重寫父類的方法和改變父類屬性耸三,會(huì)帶來一定的安全隱患,因此浇揩,當(dāng)一個(gè)類不希望被繼承時(shí)就可以使用final修飾仪壮。還是來寫一個(gè)小例子:

public final class FinalExampleParent {   public final void test() {   }}

父類會(huì)被final修飾,當(dāng)子類繼承該父類的時(shí)候胳徽,就會(huì)報(bào)錯(cuò)积锅,如下圖:

3. final的例子

final經(jīng)常會(huì)被用作不變類上,利用final的不可更改性养盗。我們先來看看什么是不變類缚陷。

不變類

不變類的意思是創(chuàng)建該類的實(shí)例后,該實(shí)例的實(shí)例變量是不可改變的往核。滿足以下條件則可以成為不可變類:

  • 使用private和final修飾符來修飾該類的成員變量

  • 提供帶參的構(gòu)造器用于初始化類的成員變量箫爷;

  • 僅為該類的成員變量提供getter方法,不提供setter方法聂儒,因?yàn)槠胀ǚ椒o法修改fina修飾的成員變量虎锚;

  • 如果有必要就重寫Object類 的hashCode()和equals()方法,應(yīng)該保證用equals()判斷相同的兩個(gè)對(duì)象其Hashcode值也是相等的衩婚。

JDK中提供的八個(gè)包裝類和String類都是不可變類窜护,我們來看看String的實(shí)現(xiàn)。

/** The value is used for character storage. */private final char value[];

可以看出String的value就是final修飾的非春,上述其他幾條性質(zhì)也是吻合的柱徙。

4. 多線程中你真的了解final嗎?

上面我們聊的final使用奇昙,應(yīng)該屬于Java基礎(chǔ)層面的坐搔,當(dāng)理解這些后我們就真的算是掌握了final嗎?有考慮過final在多線程并發(fā)的情況嗎敬矩?在java內(nèi)存模型中我們知道java內(nèi)存模型為了能讓處理器和編譯器底層發(fā)揮他們的最大優(yōu)勢(shì)概行,對(duì)底層的約束就很少,也就是說針對(duì)底層來說java內(nèi)存模型就是一弱內(nèi)存數(shù)據(jù)模型弧岳。

同時(shí)凳忙,處理器和編譯為了性能優(yōu)化會(huì)對(duì)指令序列有編譯器和處理器重排序业踏。那么,在多線程情況下,final會(huì)進(jìn)行怎樣的重排序涧卵?會(huì)導(dǎo)致線程安全的問題嗎勤家?下面,就來看看final的重排序柳恐。

4.1 final域重排序規(guī)則

4.1.1 final域?yàn)榛绢愋?/strong>

先看一段示例性的代碼:

public class FinalDemo {
   private int a;
  //普通域
   private final int b;
 //final域
   private static FinalDemo finalDemo;
   public FinalDemo() {
       a = 1; // 1\. 寫普通域
       b = 2; // 2\. 寫final域
   }   
public static void writer() {
       finalDemo = new FinalDemo();
   }  
 public static void reader() {
       FinalDemo demo = finalDemo; // 3.讀對(duì)象引用
       int a = demo.a; //4.讀普通域
       int b = demo.b;    //5.讀final域
   }}

假設(shè)線程A在執(zhí)行writer()方法伐脖,線程B執(zhí)行reader()方法。

寫final域重排序規(guī)則

寫final域的重排序規(guī)則禁止對(duì)final域的寫重排序到構(gòu)造函數(shù)之外乐设,這個(gè)規(guī)則的實(shí)現(xiàn)主要包含了兩個(gè)方面:

  • JMM禁止編譯器把final域的寫重排序到構(gòu)造函數(shù)之外讼庇;

  • 編譯器會(huì)在final域?qū)懼螅瑯?gòu)造函數(shù)return之前近尚,插入一個(gè)storestore屏障(關(guān)于內(nèi)存屏障可以看這篇文章)蠕啄。這個(gè)屏障可以禁止處理器把final域的寫重排序到構(gòu)造函數(shù)之外。

我們?cè)賮矸治鰓riter方法戈锻,雖然只有一行代碼歼跟,但實(shí)際上做了兩件事情:

  • 構(gòu)造了一個(gè)FinalDemo對(duì)象;

  • 把這個(gè)對(duì)象賦值給成員變量finalDemo格遭。

我們來畫下存在的一種可能執(zhí)行時(shí)序圖哈街,如下:

由于a,b之間沒有數(shù)據(jù)依賴性,普通域(普通變量)a可能會(huì)被重排序到構(gòu)造函數(shù)之外拒迅,線程B就有可能讀到的是普通變量a初始化之前的值(零值)骚秦,這樣就可能出現(xiàn)錯(cuò)誤。而final域變量b坪它,根據(jù)重排序規(guī)則骤竹,會(huì)禁止final修飾的變量b重排序到構(gòu)造函數(shù)之外帝牡,從而b能夠正確賦值往毡,線程B就能夠讀到final變量初始化后的值。

因此靶溜,寫final域的重排序規(guī)則可以確保:在對(duì)象引用為任意線程可見之前开瞭,對(duì)象的final域已經(jīng)被正確初始化過了,而普通域就不具有這個(gè)保障罩息。比如在上例嗤详,線程B有可能就是一個(gè)未正確初始化的對(duì)象finalDemo。

讀final域重排序規(guī)則

讀final域重排序規(guī)則為:在一個(gè)線程中瓷炮,初次讀對(duì)象引用和初次讀該對(duì)象包含的final域葱色,JMM會(huì)禁止這兩個(gè)操作的重排序。(注意娘香,這個(gè)規(guī)則僅僅是針對(duì)處理器)苍狰,處理器會(huì)在讀final域操作的前面插入一個(gè)LoadLoad屏障办龄。

實(shí)際上,讀對(duì)象的引用和讀該對(duì)象的final域存在間接依賴性淋昭,一般處理器不會(huì)重排序這兩個(gè)操作俐填。但是有一些處理器會(huì)重排序,因此翔忽,這條禁止重排序規(guī)則就是針對(duì)這些處理器而設(shè)定的英融。

read()方法主要包含了三個(gè)操作:

  • 初次讀引用變量finalDemo;

  • 初次讀引用變量finalDemo的普通域a;

  • 初次讀引用變量finalDemo的final與b;

假設(shè)線程A寫過程沒有重排序,那么線程A和線程B有一種的可能執(zhí)行時(shí)序?yàn)橄聢D:

讀對(duì)象的普通域被重排序到了讀對(duì)象引用的前面就會(huì)出現(xiàn)線程B還未讀到對(duì)象引用就在讀取該對(duì)象的普通域變量歇式,這顯然是錯(cuò)誤的操作驶悟。而final域的讀操作就“限定”了在讀final域變量前已經(jīng)讀到了該對(duì)象的引用,從而就可以避免這種情況贬丛。

讀final域的重排序規(guī)則可以確保:在讀一個(gè)對(duì)象的final域之前撩银,一定會(huì)先讀這個(gè)包含這個(gè)final域的對(duì)象的引用。

4.1.2 final域?yàn)橐妙愋?/strong>

我們已經(jīng)知道了final域是基本數(shù)據(jù)類型的時(shí)候重排序規(guī)則是怎么的了豺憔?如果是引用數(shù)據(jù)類型了额获?我們接著繼續(xù)來探討。

對(duì)final修飾的對(duì)象的成員域?qū)懖僮?/strong>

針對(duì)引用數(shù)據(jù)類型恭应,final域?qū)戓槍?duì)編譯器和處理器重排序增加了這樣的約束:在構(gòu)造函數(shù)內(nèi)對(duì)一個(gè)final修飾的對(duì)象的成員域的寫入抄邀,與隨后在構(gòu)造函數(shù)之外把這個(gè)被構(gòu)造的對(duì)象的引用賦給一個(gè)引用變量,這兩個(gè)操作是不能被重排序的昼榛。

注意這里的是“增加”也就說前面對(duì)final基本數(shù)據(jù)類型的重排序規(guī)則在這里還是使用境肾。這句話是比較拗口的,下面結(jié)合實(shí)例來看胆屿。

public class FinalReferenceDemo {
   final int[] arrays;
   private FinalReferenceDemo finalReferenceDemo;
   public FinalReferenceDemo() {
       arrays = new int[1];  //1
       arrays[0] = 1;        //2
   }
   public void writerOne() {
       finalReferenceDemo = new FinalReferenceDemo(); //3
   }
   public void writerTwo() {
       arrays[0] = 2;  //4
   }
   public void reader() {
       if (finalReferenceDemo != null) {  //5
           int temp = finalReferenceDemo.arrays[0];  //6
       }
   }}

針對(duì)上面的實(shí)例程序奥喻,線程線程A執(zhí)行wirterOne方法,執(zhí)行完后線程B執(zhí)行writerTwo方法非迹,然后線程C執(zhí)行reader方法环鲤。下圖就以這種執(zhí)行時(shí)序出現(xiàn)的一種情況來討論(耐心看完才有收獲)。

image

由于對(duì)final域的寫禁止重排序到構(gòu)造方法外憎兽,因此1和3不能被重排序冷离。由于一個(gè)final域的引用對(duì)象的成員域?qū)懭氩荒芘c隨后將這個(gè)被構(gòu)造出來的對(duì)象賦給引用變量重排序,因此2和3不能重排序纯命。

對(duì)final修飾的對(duì)象的成員域讀操作

JMM可以確保線程C至少能看到寫線程A對(duì)final引用的對(duì)象的成員域的寫入西剥,即能看下arrays[0] = 1,而寫線程B對(duì)數(shù)組元素的寫入可能看到可能看不到亿汞。JMM不保證線程B的寫入對(duì)線程C可見瞭空,線程B和線程C之間存在數(shù)據(jù)競(jìng)爭(zhēng),此時(shí)的結(jié)果是不可預(yù)知的。如果可見的咆畏,可使用鎖或者volatile图甜。

關(guān)于final重排序的總結(jié)

按照final修飾的數(shù)據(jù)類型分類:

基本數(shù)據(jù)類型:

final域?qū)懀?/strong>禁止final域?qū)懪c構(gòu)造方法重排序,即禁止final域?qū)懼嘏判虻綐?gòu)造方法之外鳖眼,從而保證該對(duì)象對(duì)所有線程可見時(shí)黑毅,該對(duì)象的final域全部已經(jīng)初始化過。

final域讀:禁止初次讀對(duì)象的引用與讀該對(duì)象包含的final域的重排序钦讳。

引用數(shù)據(jù)類型:

額外增加約束:禁止在構(gòu)造函數(shù)對(duì)一個(gè)final修飾的對(duì)象的成員域的寫入與隨后將這個(gè)被構(gòu)造的對(duì)象的引用賦值給引用變量 重排序

5.final的實(shí)現(xiàn)原理

上面我們提到過矿瘦,寫final域會(huì)要求編譯器在final域?qū)懼螅瑯?gòu)造函數(shù)返回前插入一個(gè)StoreStore屏障愿卒。讀final域的重排序規(guī)則會(huì)要求編譯器在讀final域的操作前插入一個(gè)LoadLoad屏障缚去。

很有意思的是,如果以X86處理為例琼开,X86不會(huì)對(duì)寫-寫重排序易结,所以StoreStore屏障可以省略。由于不會(huì)對(duì)有間接依賴性的操作重排序柜候,所以在X86處理器中搞动,讀final域需要的LoadLoad屏障也會(huì)被省略掉。也就是說渣刷,以X86為例的話鹦肿,對(duì)final域的讀/寫的內(nèi)存屏障都會(huì)被省略!具體是否插入還是得看是什么處理器辅柴。

6. 為什么final引用不能從構(gòu)造函數(shù)中“溢出”

這里還有一個(gè)比較有意思的問題:上面對(duì)final域?qū)懼嘏判蛞?guī)則可以確保我們?cè)谑褂靡粋€(gè)對(duì)象引用的時(shí)候該對(duì)象的final域已經(jīng)在構(gòu)造函數(shù)被初始化過了箩溃。

但是這里其實(shí)是有一個(gè)前提條件的,也就是:在構(gòu)造函數(shù)碌嘀,不能讓這個(gè)被構(gòu)造的對(duì)象被其他線程可見涣旨,也就是說該對(duì)象引用不能在構(gòu)造函數(shù)中“逸出”。以下面的例子來說:

public class FinalReferenceEscapeDemo {
   private final int a;
   private FinalReferenceEscapeDemo referenceDemo;
   public FinalReferenceEscapeDemo() {
       a = 1;  //1
       referenceDemo = this; //2
   }
   public void writer() {
       new FinalReferenceEscapeDemo(); 
  }   public void reader() {
       if (referenceDemo != null) {  //3
           int temp = referenceDemo.a; //4 
      }
   }
}

可能的執(zhí)行時(shí)序如圖所示:

假設(shè)一個(gè)線程A執(zhí)行writer方法另一個(gè)線程執(zhí)行reader方法股冗。因?yàn)闃?gòu)造函數(shù)中操作1和2之間沒有數(shù)據(jù)依賴性霹陡,1和2可以重排序,先執(zhí)行了2魁瞪,這個(gè)時(shí)候引用對(duì)象referenceDemo是個(gè)沒有完全初始化的對(duì)象穆律,而當(dāng)線程B去讀取該對(duì)象時(shí)就會(huì)出錯(cuò)惠呼。

盡管依然滿足了final域?qū)懼嘏判蛞?guī)則:在引用對(duì)象對(duì)所有線程可見時(shí)导俘,其final域已經(jīng)完全初始化成功。但是剔蹋,引用對(duì)象“this”逸出旅薄,該代碼依然存在線程安全的問題。

原創(chuàng): Java菜鳥奮斗史 [Java知音] https://mp.weixin.qq.com/s/e6Z0U9zdqUiuNXycdyV_PQ

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市少梁,隨后出現(xiàn)的幾起案子洛口,更是在濱河造成了極大的恐慌,老刑警劉巖凯沪,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件第焰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡妨马,警方通過查閱死者的電腦和手機(jī)挺举,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烘跺,“玉大人湘纵,你說我怎么就攤上這事÷舜荆” “怎么了梧喷?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)脖咐。 經(jīng)常有香客問我铺敌,道長(zhǎng),這世上最難降的妖魔是什么屁擅? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任适刀,我火速辦了婚禮,結(jié)果婚禮上煤蹭,老公的妹妹穿的比我還像新娘笔喉。我一直安慰自己,他們只是感情好硝皂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布常挚。 她就那樣靜靜地躺著,像睡著了一般稽物。 火紅的嫁衣襯著肌膚如雪奄毡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天贝或,我揣著相機(jī)與錄音吼过,去河邊找鬼。 笑死咪奖,一個(gè)胖子當(dāng)著我的面吹牛盗忱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播羊赵,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼趟佃,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闲昭,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤罐寨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后序矩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸯绿,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年簸淀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了楞慈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啃擦,死狀恐怖囊蓝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情令蛉,我是刑警寧澤聚霜,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站珠叔,受9級(jí)特大地震影響蝎宇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜祷安,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一姥芥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汇鞭,春花似錦凉唐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至读整,卻和暖如春簿训,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背米间。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工强品, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屈糊。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓的榛,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親另玖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子困曙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 目錄: 1. 指令重排 2. 順序一致性 3. volatile 4. final 1.指令重排 要了解指令重排,...
    西部小籠包閱讀 746評(píng)論 0 1
  • 原創(chuàng)文章&經(jīng)驗(yàn)總結(jié)&從校招到A廠一路陽光一路滄桑 詳情請(qǐng)戳www.codercc.com 1. final的簡(jiǎn)介 ...
    你聽___閱讀 8,000評(píng)論 6 22
  • We are not surprised by modern sculpture any more as som...
    化真閱讀 393評(píng)論 0 1
  • 2017.6.13 有臺(tái)風(fēng),苗柏 今早從黃色降為藍(lán)色 瑣事記錄 昨天兒子兩個(gè)同學(xué)來玩鳄哭,同學(xué)走后兒子不高興要糊,慢慢說了...
    carol曉霞閱讀 139評(píng)論 0 0
  • 所畫之人是當(dāng)年老山”硬骨頭排“的排長(zhǎng) 當(dāng)年他的一個(gè)排戰(zhàn)友在一場(chǎng)老山守衛(wèi)戰(zhàn)役中全部犧牲!僅存他一人還被炸瞎了雙眼 他...
    匠人無愚閱讀 220評(píng)論 0 3