物理內(nèi)存 :
??由于計(jì)算機(jī)的存儲(chǔ)設(shè)備與處理器的運(yùn)算速度有幾個(gè)數(shù)量級(jí)的差距, 所以現(xiàn)代計(jì)算機(jī)系統(tǒng)都不得不加入一層讀寫速度盡可能接近處理器運(yùn)算速度的高速緩存來作為內(nèi)存與處理器之間的緩存: 將運(yùn)算需要使用到的數(shù)據(jù)復(fù)制到緩存中, 讓運(yùn)算能快速進(jìn)行, 當(dāng)運(yùn)算結(jié)束后再從緩存同步回內(nèi)存中, 這樣處理器就無須等待緩慢的內(nèi)存讀寫了;
緩存一致性 :
??在多處理器系統(tǒng)中, 每個(gè)處理器都有自己的高速緩存, 而它們又共享同一主內(nèi)存. 當(dāng)多個(gè)處理器的運(yùn)算任務(wù)都涉及同一塊主內(nèi)存區(qū)域時(shí), 將可能導(dǎo)致各自的緩存數(shù)據(jù)不一致.

指令重排序 :
??為了使得處理器內(nèi)部的運(yùn)算單元能盡量被充分利用, 處理器可能會(huì)對(duì)輸入代碼進(jìn)行亂序執(zhí)行優(yōu)化, 處理器會(huì)在計(jì)算之后將亂序執(zhí)行的結(jié)果重組, 保證該結(jié)果與順序執(zhí)行的結(jié)果是一致的, 但并不保證程序中各個(gè)語句計(jì)算的先后順序與輸入代碼的順序一致, 因此, 如果存在一個(gè)計(jì)算任務(wù)依賴另一個(gè)計(jì)算任務(wù)的中間結(jié)果, 那么其順序性并不能靠代碼的先后順序來保證;
java內(nèi)存模型 :
??1、java內(nèi)存模型的主要目標(biāo)是定義程序中各個(gè)變量的訪問規(guī)則, 此處的變量包括了實(shí)例字段, 靜態(tài)字段和構(gòu)成數(shù)組對(duì)象的元素, 但不包括局部變量與方法參數(shù), 因?yàn)楹笳呤蔷€程私有的, 不會(huì)被共享, 不會(huì)存在競(jìng)爭(zhēng)的問題;
??2、java內(nèi)存模型規(guī)定了所有的變量都存儲(chǔ)在主內(nèi)存中. 每條線程還有自己的工作內(nèi)存, 線程的工作內(nèi)存中保存了該線程使用到的變量的主內(nèi)存副本拷貝, 線程對(duì)變量的所有操作(讀取, 賦值等)都必須在工作內(nèi)存中進(jìn)行, 而不能直接讀寫主內(nèi)存中的變量.
??3、不同的線程之間也無法直接訪問對(duì)方工作內(nèi)存中的變量, 線程間變量值得傳遞均需要通過主內(nèi)存來完成.
??4、工作內(nèi)存對(duì)應(yīng)虛擬機(jī)棧中的部分區(qū)域, 主內(nèi)存對(duì)應(yīng)于物理硬件的內(nèi)存;

內(nèi)存間交互 :
??主內(nèi)存與工作內(nèi)存之間具體的交互協(xié)議 : java內(nèi)存模型中定義了以下8種操作來完成, 一個(gè)變量在主內(nèi)存和工作內(nèi)存之間的交互的實(shí)現(xiàn)細(xì)節(jié), 虛擬機(jī)實(shí)現(xiàn)時(shí)必須保證下面提及的每一種操作都是原子的、不可再分的;
- 1、lock(鎖定) : 作用于主內(nèi)存的變量, 它把一個(gè)變量標(biāo)識(shí)為一條線程獨(dú)占的狀態(tài);
- 2、unlock(解鎖) : 作用于主內(nèi)存的變量, 它把一個(gè)處于鎖定狀態(tài)的變量釋放出來, 釋放后的變量才可以被其他線程鎖定;
- 3、read(讀取) : 作用于主內(nèi)存的變量, 它把一個(gè)變量的值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中, 以便隨后的load動(dòng)作使用;
- 4、load(載入) : 作用于工作內(nèi)存的變量, 它把read操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中;
- 5、use(使用) : 作用于工作內(nèi)存的變量, 它把工作內(nèi)存中一個(gè)變量的值傳遞給執(zhí)行引擎, 每當(dāng)虛擬機(jī)遇到一個(gè)需要使用的變量的值得字節(jié)碼指令時(shí)將會(huì)執(zhí)行這個(gè)操作;
- 6、assign(賦值) : 作用于工作內(nèi)存的變量, 它把一個(gè)從執(zhí)行引擎接收到的值賦給工作內(nèi)存的變量, 每當(dāng)虛擬機(jī)遇到一個(gè)給變量賦值的字節(jié)碼指令時(shí)執(zhí)行這個(gè)操作;
- 7、store(存儲(chǔ)) : 作用于工作內(nèi)存的變量, 它把工作內(nèi)存中一個(gè)變量的值傳送到主內(nèi)存中, 以便隨后的write操作使用;
- 8、write(寫入) : 作用于主內(nèi)存的變量, 它把store操作從工作內(nèi)存中得到的變量的值放入主內(nèi)存的變量中;
volatile :
??1、可見性 : 保證變量對(duì)所有線程可見, 當(dāng)一條線程修改了這個(gè)變量的值, 新值對(duì)于其他線程來說是可以立即得知的;
??2、禁止指令重排序 : 指令重排序是指CPU采用了允許將多條指令不按程序規(guī)定的順序分開發(fā)送給各相應(yīng)電路單元處理.
??分別用兩段常見代碼來闡述volatile這兩個(gè)特性 :
可見性(但不能保證原子性):
public class Instance {
private static int i;
public static void increase() {
i++;
}
}
??上面代碼實(shí)際要分為以下幾個(gè)步驟:
1. 將變量i讀取到工作內(nèi)存中;
2. int var = i + 1;操作賦值給var變量;
3. var變量再賦值給i;
4. i回寫到主內(nèi)存中;
??所以當(dāng)多個(gè)內(nèi)存同時(shí)調(diào)用increase()方法時(shí), 可能線程_1執(zhí)行到步驟2時(shí), 線程_2也執(zhí)行到步驟2, 就會(huì)導(dǎo)致increase()被兩個(gè)線程分別調(diào)用一次, 但是i實(shí)際為1的線程;
禁止指令重排序 :
public class Instance {
private static Instance instance;
public static Instance getInstance() {
if (instance == null) {
synchronized(Instance.class) {
if (instance == null ) {
instance = new Instance();
}
}
}
return instance;
}
}
??instance = new Instance()可以分為以下幾個(gè)步驟 :
- 1、棧內(nèi)存開辟空間給instance使用;
- 2、堆內(nèi)存開辟空間準(zhǔn)備初始化對(duì)象;
- 3、初始化對(duì)象;
- 4、棧中引用指向這個(gè)堆內(nèi)存空間地址;
??但是由于指令重排序, 上述步驟也可能實(shí)際執(zhí)行順序?yàn)?_2_4_3;按照這個(gè)順序, 當(dāng)線程1執(zhí)行到步驟4時(shí), 線程2調(diào)用getInstance()方法發(fā)現(xiàn)instance此時(shí)已經(jīng)被賦值一個(gè)引用 != null, 直接走return方法, 但是此時(shí)instance所指向的Instance對(duì)象并沒有初始化完成, 即內(nèi)部變量都還是默認(rèn)值;
線程的實(shí)現(xiàn) :
實(shí)現(xiàn)線程主要有3種方式 : 使用內(nèi)核線程、使用用戶線程和使用用戶線程加輕量級(jí)進(jìn)程混合;
1、使用內(nèi)核線程實(shí)現(xiàn) :
??
線程的狀態(tài) :
??java語言定義了6種線程狀態(tài), 在任意一個(gè)時(shí)間點(diǎn), 一個(gè)線程只能有且僅有其中的一個(gè)狀態(tài):
- 1、新建(New) : 創(chuàng)建后尚未啟動(dòng)的線程處于這種狀態(tài);
- 2、運(yùn)行(Runnable) : Runnable包括了操作系統(tǒng)線程狀態(tài)中的Running和Ready, 也就是處于此狀態(tài)的線程有可能正在執(zhí)行, 也有可能正在等待著CPU為它分配執(zhí)行時(shí)間;
- 3、無限期等待(Waiting) : 處于這種狀態(tài)的線程不會(huì)被分配CPU執(zhí)行時(shí)間, 它們要等待被其他線程顯示的喚醒. 以下方法會(huì)讓線程陷入無限期的等待狀態(tài);
1. 沒有設(shè)置Timeout參數(shù)的Object.wait()方法;
2. 沒有設(shè)置Timeout參數(shù)的Thread.join()方法;
3. LockSupport.park()方法;
- 4、限期等待(Time Waiting) : 處于這種狀態(tài)的線程也不會(huì)被分配CPU執(zhí)行時(shí)間, 不過無須等待被其他線程顯示的喚醒, 在一定時(shí)間之后它們會(huì)由系統(tǒng)自動(dòng)喚醒. 以下方法會(huì)讓線程進(jìn)入限期等待狀態(tài):
1. Thread.sleep()方法;
2. 設(shè)置了Timeout參數(shù)的Object.wait()方法;
3. 設(shè)置了Timeout參數(shù)的Thread.join()方法;
4. LockSupport.parkNanos()方法;
5. LockSupport.parkUnitl()方法;
- 5、阻塞(Blocked) : 線程被阻塞了, "阻塞狀態(tài)"與"等待狀態(tài)"的區(qū)別是: "阻塞狀態(tài)"在等待著獲取到一個(gè)排他鎖, 這個(gè)事件將在另外一個(gè)線程放棄這個(gè)鎖的時(shí)候發(fā)生; 而"等待狀態(tài)"則是在等待一段時(shí)間, 或者喚醒動(dòng)作的發(fā)生. 在程序等待進(jìn)入同步區(qū)域的時(shí)候, 線程將進(jìn)入這種狀態(tài);
- 6、結(jié)束(Terminated) : 已終止線程的線程狀態(tài), 線程已經(jīng)結(jié)束執(zhí)行;