java基礎(chǔ)之變量與內(nèi)存(1)

該章節(jié)討論java變量奕塑,主要分為基本(數(shù)據(jù))類(lèi)型和引用類(lèi)型丰歌,以及變量在內(nèi)存堆棧中的存儲(chǔ)议蟆。

基本類(lèi)型:

布爾型:boolean(1)婚温; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?整型:byte(8),short(16),int(32),long(64); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?字符型:char(16)儡湾; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 浮點(diǎn)型:float(32),double(64)特恬。

因?yàn)閖ava是使用虛擬機(jī)的跨平臺(tái)語(yǔ)言,所以java的這幾個(gè)類(lèi)型的長(zhǎng)度是不會(huì)隨著使用系統(tǒng)的不同而發(fā)生位數(shù)的變化的(這點(diǎn)不同于C++) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?基本類(lèi)型是可以進(jìn)行轉(zhuǎn)換的包括:自動(dòng)類(lèi)型轉(zhuǎn)換和強(qiáng)制類(lèi)型轉(zhuǎn)換徐钠。

自動(dòng)類(lèi)型轉(zhuǎn)換

強(qiáng)制類(lèi)型轉(zhuǎn)換:當(dāng)?shù)途鹊臄?shù)據(jù)轉(zhuǎn)化為高精度的數(shù)據(jù)時(shí)癌刽,數(shù)據(jù)值不會(huì)丟失,反之會(huì)影響數(shù)據(jù)精度

引用類(lèi)型:類(lèi)尝丐,接口显拜,數(shù)組(null也可作為一個(gè)類(lèi)型);

數(shù)組類(lèi)型: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?定義數(shù)組:type[] arrayName;或者 type arrayName[]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 初始化數(shù)組: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?靜態(tài)初始化:arrayName = new type[]{element1,element2,element3...}; 如:int[] a = {5,6,7,8}; ? ? ? ? ? ? ? 動(dòng)態(tài)初始化:arrayName = new type[length];如:int a = new int[5]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?數(shù)組在內(nèi)存中是占用連續(xù)的內(nèi)存空間爹袁,所以數(shù)組的運(yùn)行效率比較高優(yōu)于集合远荠。數(shù)組的引用變量是存放在棧內(nèi)存中,引用的實(shí)際數(shù)組存放在堆內(nèi)存中失息。數(shù)組變量引用的是數(shù)組在堆內(nèi)存中的首地址譬淳,當(dāng)使用具體下標(biāo)查找某個(gè)數(shù)組時(shí)指向的是該對(duì)應(yīng)數(shù)據(jù)的引用地址。

String類(lèi):首先String是不可變的盹兢,一旦生成值就不可以再改變邻梆,可以另外生成一個(gè)新的String,改變引用绎秒,但是不會(huì)改變之前生成的String浦妄。如下:部分String源碼

public final class String implement java.io.Seriallizable,Comparable<String>,CharSequence{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?private final char value[]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?private final int offset; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? private final int count; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?private int hash; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

從代碼中可以看出來(lái),String類(lèi)其實(shí)是對(duì)字符數(shù)組的封裝替裆,value是封裝的數(shù)組校辩,offset是這個(gè)value數(shù)組的初始位置,count是數(shù)組所占字符的個(gè)數(shù)窘问。從代碼中可以看出來(lái)辆童,所提供的這幾個(gè)變量全都是private的,并且由final修飾(當(dāng)然這些也是引用惠赫,是可以通過(guò)反射修改的)把鉴。實(shí)際的String內(nèi)存存儲(chǔ)情況為


關(guān)于String str0 = "hello";String str1 = "hello";和String str2 = new String("hello");String str3 = new String("hello");"hello"是在編譯器就確定的存放在常量池中,str0和str1指向的是常量池中的同一個(gè)對(duì)象儿咱,而str2和str3指向的是對(duì)象庭砍,存放在堆內(nèi)存中是不同的對(duì)象。

關(guān)于String str1 = "ab"+"cd"+"ef"; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 與 ? ?StringBuffer str2 =new StringBuffer();str2.append(cd);str2.append("ef") ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 創(chuàng)建的字符個(gè)數(shù):在str1中首先肯定生成了"ab","cd","ef",三個(gè)變量混埠,然后又生成了"abcd"中間變量怠缸,最后生成了"abcdef"變量,也就是生成了五個(gè)String變量钳宪。而str2始終一直是只有一個(gè)StringBuffer變量揭北。所以效率之間的比較也就一目了然扳炬。

詳細(xì)內(nèi)存分析:

Java內(nèi)存模型把Java虛擬機(jī)內(nèi)部劃分為線程棧和堆。這張圖演示了Java內(nèi)存模型的邏輯視圖搔体。

每一個(gè)運(yùn)行在Java虛擬機(jī)里的線程都擁有自己的線程棧恨樟。這個(gè)線程棧包含了這個(gè)線程調(diào)用的方法當(dāng)前執(zhí)行點(diǎn)相關(guān)的信息。一個(gè)線程僅能訪問(wèn)自己的線程棧疚俱。一個(gè)線程創(chuàng)建的本地變量對(duì)其它線程不可見(jiàn)劝术,僅自己可見(jiàn)。即使兩個(gè)線程執(zhí)行同樣的代碼呆奕,這兩個(gè)線程任然在在自己的線程棧中的代碼來(lái)創(chuàng)建本地變量养晋。因此,每個(gè)線程擁有每個(gè)本地變量的獨(dú)有版本登馒。

所有原始類(lèi)型的本地變量都存放在線程棧上匙握,因此對(duì)其它線程不可見(jiàn)。一個(gè)線程可能向另一個(gè)線程傳遞一個(gè)原始類(lèi)型變量的拷貝陈轿,但是它不能共享這個(gè)原始類(lèi)型變量自身圈纺。

堆上包含在Java程序中創(chuàng)建的所有對(duì)象,無(wú)論是哪一個(gè)對(duì)象創(chuàng)建的麦射。這包括原始類(lèi)型的對(duì)象版本蛾娶。如果一個(gè)對(duì)象被創(chuàng)建然后賦值給一個(gè)局部變量,或者用來(lái)作為另一個(gè)對(duì)象的成員變量潜秋,這個(gè)對(duì)象任然是存放在堆上蛔琅。下面這張圖演示了調(diào)用棧和本地變量存放在線程棧上,對(duì)象存放在堆上峻呛。

一個(gè)本地變量可能是原始類(lèi)型罗售,在這種情況下,它總是“呆在”線程棧上钩述。

一個(gè)本地變量也可能是指向一個(gè)對(duì)象的一個(gè)引用寨躁。在這種情況下,引用(這個(gè)本地變量)存放在線程棧上牙勘,但是對(duì)象本身存放在堆上职恳。

一個(gè)對(duì)象可能包含方法,這些方法可能包含本地變量方面。這些本地變量任然存放在線程棧上放钦,即使這些方法所屬的對(duì)象存放在堆上。

一個(gè)對(duì)象的成員變量可能隨著這個(gè)對(duì)象自身存放在堆上恭金。不管這個(gè)成員變量是原始類(lèi)型還是引用類(lèi)型操禀。

靜態(tài)成員變量跟隨著類(lèi)定義一起也存放在堆上。

存放在堆上的對(duì)象可以被所有持有對(duì)這個(gè)對(duì)象引用的線程訪問(wèn)横腿。當(dāng)一個(gè)線程可以訪問(wèn)一個(gè)對(duì)象時(shí)颓屑,它也可以訪問(wèn)這個(gè)對(duì)象的成員變量辙培。如果兩個(gè)線程同時(shí)調(diào)用同一個(gè)對(duì)象上的同一個(gè)方法,它們將會(huì)都訪問(wèn)這個(gè)對(duì)象的成員變量邢锯,但是每一個(gè)線程都擁有這個(gè)本地變量的私有拷貝扬蕊。

下圖演示了上面提到的點(diǎn):

兩個(gè)線程擁有一些列的本地變量。其中一個(gè)本地變量(Local Variable 2)執(zhí)行堆上的一個(gè)共享對(duì)象(Object 3)丹擎。這兩個(gè)線程分別擁有同一個(gè)對(duì)象的不同引用尾抑。這些引用都是本地變量,因此存放在各自線程的線程棧上蒂培。這兩個(gè)不同的引用指向堆上同一個(gè)對(duì)象再愈。

注意,這個(gè)共享對(duì)象(Object 3)持有Object2和Object4一個(gè)引用作為其成員變量(如圖中Object3指向Object2和Object4的箭頭)护戳。通過(guò)在Object3中這些成員變量引用翎冲,這兩個(gè)線程就可以訪問(wèn)Object2和Object4。

這張圖也展示了指向堆上兩個(gè)不同對(duì)象的一個(gè)本地變量媳荒。在這種情況下抗悍,指向兩個(gè)不同對(duì)象的引用不是同一個(gè)對(duì)象。理論上钳枕,兩個(gè)線程都可以訪問(wèn)Object1和Object5缴渊,如果兩個(gè)線程都擁有兩個(gè)對(duì)象的引用。但是在上圖中鱼炒,每一個(gè)線程僅有一個(gè)引用指向兩個(gè)對(duì)象其中之一衔沼。

public class MyRunnable implements Runnable() {? ? public void run() {

methodOne();

}? ? public void methodOne() {? ? ? ? int localVariable1 = 45;

MySharedObject localVariable2 =

MySharedObject.sharedInstance;? ? ? ? //... do more with local variables.

methodTwo();

}? ? public void methodTwo() {

Integer localVariable1 = new Integer(99);? ? ? ? //... do more with local variable.

}}

public class MySharedObject {? ? //static variable pointing to instance of MySharedObject

public static final MySharedObject sharedInstance =? ? ? ? new MySharedObject();? ? //member variables pointing to two objects on the heap

public Integer object2 = new Integer(22);? ? public Integer object4 = new Integer(44);? ? public long member1 = 12345;? ? public long member1 = 67890;

}

如果兩個(gè)線程同時(shí)執(zhí)行run()方法,就會(huì)出現(xiàn)上圖所示的情景昔瞧。run()方法調(diào)用methodOne()方法指蚁,methodOne()調(diào)用methodTwo()方法。

methodOne()聲明了一個(gè)原始類(lèi)型的本地變量和一個(gè)引用類(lèi)型的本地變量自晰。

每個(gè)線程執(zhí)行methodOne()都會(huì)在它們對(duì)應(yīng)的線程棧上創(chuàng)建localVariable1和localVariable2的私有拷貝凝化。localVariable1變量彼此完全獨(dú)立,僅“生活”在每個(gè)線程的線程棧上缀磕。一個(gè)線程看不到另一個(gè)線程對(duì)它的localVariable1私有拷貝做出的修改缘圈。

每個(gè)線程執(zhí)行methodOne()時(shí)也將會(huì)創(chuàng)建它們各自的localVariable2拷貝劣光。然而袜蚕,兩個(gè)localVariable2的不同拷貝都指向堆上的同一個(gè)對(duì)象。代碼中通過(guò)一個(gè)靜態(tài)變量設(shè)置localVariable2指向一個(gè)對(duì)象引用绢涡。僅存在一個(gè)靜態(tài)變量的一份拷貝牲剃,這份拷貝存放在堆上。因此雄可,localVariable2的兩份拷貝都指向由MySharedObject指向的靜態(tài)變量的同一個(gè)實(shí)例凿傅。MySharedObject實(shí)例也存放在堆上缠犀。它對(duì)應(yīng)于上圖中的Object3。

注意聪舒,MySharedObject類(lèi)也包含兩個(gè)成員變量辨液。這些成員變量隨著這個(gè)對(duì)象存放在堆上。這兩個(gè)成員變量指向另外兩個(gè)Integer對(duì)象箱残。這些Integer對(duì)象對(duì)應(yīng)于上圖中的Object2和Object4.

注意滔迈,methodTwo()創(chuàng)建一個(gè)名為localVariable的本地變量。這個(gè)成員變量是一個(gè)指向一個(gè)Integer對(duì)象的對(duì)象引用被辑。這個(gè)方法設(shè)置localVariable1引用指向一個(gè)新的Integer實(shí)例燎悍。在執(zhí)行methodTwo方法時(shí),localVariable1引用將會(huì)在每個(gè)線程中存放一份拷貝盼理。這兩個(gè)Integer對(duì)象實(shí)例化將會(huì)被存儲(chǔ)堆上谈山,但是每次執(zhí)行這個(gè)方法時(shí),這個(gè)方法都會(huì)創(chuàng)建一個(gè)新的Integer對(duì)象宏怔,兩個(gè)線程執(zhí)行這個(gè)方法將會(huì)創(chuàng)建兩個(gè)不同的Integer實(shí)例奏路。methodTwo方法創(chuàng)建的Integer對(duì)象對(duì)應(yīng)于上圖中的Object1和Object5。

還有一點(diǎn)臊诊,MySharedObject類(lèi)中的兩個(gè)long類(lèi)型的成員變量是原始類(lèi)型的思劳。因?yàn)椋@些變量是成員變量妨猩,所以它們?nèi)稳浑S著該對(duì)象存放在堆上潜叛,僅有本地變量存放在線程棧上。

硬件內(nèi)存架構(gòu)

現(xiàn)代硬件內(nèi)存模型與Java內(nèi)存模型有一些不同壶硅。理解內(nèi)存模型架構(gòu)以及Java內(nèi)存模型如何與它協(xié)同工作也是非常重要的威兜。這部分描述了通用的硬件內(nèi)存架構(gòu),下面的部分將會(huì)描述Java內(nèi)存是如何與它“聯(lián)手”工作的庐椒。

下面是現(xiàn)代計(jì)算機(jī)硬件架構(gòu)的簡(jiǎn)單圖示:

一個(gè)現(xiàn)代計(jì)算機(jī)通常由兩個(gè)或者多個(gè)CPU椒舵。其中一些CPU還有多核。從這一點(diǎn)可以看出约谈,在一個(gè)有兩個(gè)或者多個(gè)CPU的現(xiàn)代計(jì)算機(jī)上同時(shí)運(yùn)行多個(gè)線程是可能的笔宿。每個(gè)CPU在某一時(shí)刻運(yùn)行一個(gè)線程是沒(méi)有問(wèn)題的。這意味著棱诱,如果你的Java程序是多線程的泼橘,在你的Java程序中每個(gè)CPU上一個(gè)線程可能同時(shí)(并發(fā))執(zhí)行。

每個(gè)CPU都包含一系列的寄存器迈勋,它們是CPU內(nèi)內(nèi)存的基礎(chǔ)炬灭。CPU在寄存器上執(zhí)行操作的速度遠(yuǎn)大于在主存上執(zhí)行的速度。這是因?yàn)镃PU訪問(wèn)寄存器的速度遠(yuǎn)大于主存靡菇。

每個(gè)CPU可能還有一個(gè)CPU緩存層重归。實(shí)際上米愿,絕大多數(shù)的現(xiàn)代CPU都有一定大小的緩存層。CPU訪問(wèn)緩存層的速度快于訪問(wèn)主存的速度鼻吮,但通常比訪問(wèn)內(nèi)部寄存器的速度還要慢一點(diǎn)育苟。一些CPU還有多層緩存,但這些對(duì)理解Java內(nèi)存模型如何和內(nèi)存交互不是那么重要椎木。只要知道CPU中可以有一個(gè)緩存層就可以了宙搬。

一個(gè)計(jì)算機(jī)還包含一個(gè)主存。所有的CPU都可以訪問(wèn)主存拓哺。主存通常比CPU中的緩存大得多勇垛。

通常情況下,當(dāng)一個(gè)CPU需要讀取主存時(shí)士鸥,它會(huì)將主存的部分讀到CPU緩存中闲孤。它甚至可能將緩存中的部分內(nèi)容讀到它的內(nèi)部寄存器中,然后在寄存器中執(zhí)行操作烤礁。當(dāng)CPU需要將結(jié)果寫(xiě)回到主存中去時(shí)讼积,它會(huì)將內(nèi)部寄存器的值刷新到緩存中,然后在某個(gè)時(shí)間點(diǎn)將值刷新回主存脚仔。

當(dāng)CPU需要在緩存層存放一些東西的時(shí)候勤众,存放在緩存中的內(nèi)容通常會(huì)被刷新回主存。CPU緩存可以在某一時(shí)刻將數(shù)據(jù)局部寫(xiě)到它的內(nèi)存中鲤脏,和在某一時(shí)刻局部刷新它的內(nèi)存们颜。它不會(huì)再某一時(shí)刻讀/寫(xiě)整個(gè)緩存。通常猎醇,在一個(gè)被稱(chēng)作“cache lines”的更小的內(nèi)存塊中緩存被更新窥突。一個(gè)或者多個(gè)緩存行可能被讀到緩存,一個(gè)或者多個(gè)緩存行可能再被刷新回主存硫嘶。

Java內(nèi)存模型和硬件內(nèi)存架構(gòu)之間的橋接

上面已經(jīng)提到阻问,Java內(nèi)存模型與硬件內(nèi)存架構(gòu)之間存在差異。硬件內(nèi)存架構(gòu)沒(méi)有區(qū)分線程棧和堆沦疾。對(duì)于硬件称近,所有的線程棧和堆都分布在主內(nèi)中。部分線程棧和堆可能有時(shí)候會(huì)出現(xiàn)在CPU緩存中和CPU內(nèi)部的寄存器中哮塞。如下圖所示:

當(dāng)對(duì)象和變量被存放在計(jì)算機(jī)中各種不同的內(nèi)存區(qū)域中時(shí)刨秆,就可能會(huì)出現(xiàn)一些具體的問(wèn)題。主要包括如下兩個(gè)方面:

線程對(duì)共享變量修改的可見(jiàn)性

當(dāng)讀彻桃,寫(xiě)和檢查共享變量時(shí)出現(xiàn)race conditions

下面我們專(zhuān)門(mén)來(lái)解釋以下這兩個(gè)問(wèn)題坛善。

共享對(duì)象可見(jiàn)性

如果兩個(gè)或者更多的線程在沒(méi)有正確的使用Volatile聲明或者同步的情況下共享一個(gè)對(duì)象晾蜘,一個(gè)線程更新這個(gè)共享對(duì)象可能對(duì)其它線程來(lái)說(shuō)是不接見(jiàn)的邻眷。

想象一下眠屎,共享對(duì)象被初始化在主存中。跑在CPU上的一個(gè)線程將這個(gè)共享對(duì)象讀到CPU緩存中肆饶。然后修改了這個(gè)對(duì)象改衩。只要CPU緩存沒(méi)有被刷新會(huì)主存,對(duì)象修改后的版本對(duì)跑在其它CPU上的線程都是不可見(jiàn)的驯镊。這種方式可能導(dǎo)致每個(gè)線程擁有這個(gè)共享對(duì)象的私有拷貝葫督,每個(gè)拷貝停留在不同的CPU緩存中。

下圖示意了這種情形板惑。跑在左邊CPU的線程拷貝這個(gè)共享對(duì)象到它的CPU緩存中橄镜,然后將count變量的值修改為2。這個(gè)修改對(duì)跑在右邊CPU上的其它線程是不可見(jiàn)的冯乘,因?yàn)樾薷暮蟮腸ount的值還沒(méi)有被刷新回主存中去洽胶。

解決這個(gè)問(wèn)題你可以使用Java中的volatile關(guān)鍵字。volatile關(guān)鍵字可以保證直接從主存中讀取一個(gè)變量裆馒,如果這個(gè)變量被修改后姊氓,總是會(huì)被寫(xiě)回到主存中去。

Race Conditions

如果兩個(gè)或者更多的線程共享一個(gè)對(duì)象喷好,多個(gè)線程在這個(gè)共享對(duì)象上更新變量翔横,就有可能發(fā)生race conditions。

想象一下梗搅,如果線程A讀一個(gè)共享對(duì)象的變量count到它的CPU緩存中禾唁。再想象一下,線程B也做了同樣的事情无切,但是往一個(gè)不同的CPU緩存中◇翱。現(xiàn)在線程A將count加1,線程B也做了同樣的事情《┪恚現(xiàn)在count已經(jīng)被增在了兩個(gè)肢预,每個(gè)CPU緩存中一次。

如果這些增加操作被順序的執(zhí)行洼哎,變量count應(yīng)該被增加兩次烫映,然后原值+2被寫(xiě)回到主存中去。

然而噩峦,兩次增加都是在沒(méi)有適當(dāng)?shù)耐较虏l(fā)執(zhí)行的锭沟。無(wú)論是線程A還是線程B將count修改后的版本寫(xiě)回到主存中取,修改后的值僅會(huì)被原值大1识补,盡管增加了兩次族淮。

下圖演示了上面描述的情況:

解決這個(gè)問(wèn)題可以使用Java同步塊。一個(gè)同步塊可以保證在同一時(shí)刻僅有一個(gè)線程可以進(jìn)入代碼的臨界區(qū)。同步塊還可以保證代碼塊中所有被訪問(wèn)的變量將會(huì)從主存中讀入祝辣,當(dāng)線程退出同步代碼塊時(shí)贴妻,所有被更新的變量都會(huì)被刷新回主存中去,不管這個(gè)變量是否被聲明為volatile蝙斜。


以上內(nèi)存部分基本是參考一下地址內(nèi)容:https://buluo.qq.com/p/detail.html?bid=11314&pid=9062246-1480229191&from=share_copylink

如有版權(quán)問(wèn)題名惩,請(qǐng)告知修改

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市孕荠,隨后出現(xiàn)的幾起案子娩鹉,更是在濱河造成了極大的恐慌,老刑警劉巖稚伍,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弯予,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡个曙,警方通過(guò)查閱死者的電腦和手機(jī)熙涤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)困檩,“玉大人祠挫,你說(shuō)我怎么就攤上這事〉垦兀” “怎么了等舔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)糟趾。 經(jīng)常有香客問(wèn)我慌植,道長(zhǎng),這世上最難降的妖魔是什么义郑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任蝶柿,我火速辦了婚禮,結(jié)果婚禮上非驮,老公的妹妹穿的比我還像新娘交汤。我一直安慰自己,他們只是感情好劫笙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布芙扎。 她就那樣靜靜地躺著,像睡著了一般填大。 火紅的嫁衣襯著肌膚如雪戒洼。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天允华,我揣著相機(jī)與錄音圈浇,去河邊找鬼寥掐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛磷蜀,可吹牛的內(nèi)容都是我干的召耘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蠕搜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼怎茫!你這毒婦竟也來(lái)了收壕?” 一聲冷哼從身側(cè)響起妓灌,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜜宪,沒(méi)想到半個(gè)月后虫埂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡圃验,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年掉伏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澳窑。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡斧散,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出摊聋,到底是詐尸還是另有隱情鸡捐,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布麻裁,位于F島的核電站箍镜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏煎源。R本人自食惡果不足惜色迂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望手销。 院中可真熱鬧歇僧,春花似錦、人聲如沸锋拖。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)姑隅。三九已至写隶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讲仰,已是汗流浹背慕趴。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冕房。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓躏啰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親耙册。 傳聞我的和親對(duì)象是個(gè)殘疾皇子给僵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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