因爲計算機的存儲設備與處理器的運算速度有幾個數量級的差距,因此現代計算機系統都不得不加入一層讀寫速度儘量接近處理器運算速度的高速緩存(Cache)來做爲內存與處理器之間的緩衝:將運算須要使用到的數據複製到緩存中,讓運算能快速進行,當運算結束後再從緩存同步回內存之中,這樣處理器就無須等待緩慢的內存讀寫了。java
基於高速緩存的存儲交互很好地解決了處理器與內存的速度矛盾,可是也爲計算機系統帶來更高的複雜度,由於它引入了一個新的問題:緩存一致性(Cache Coherence)。在多處理器系統中,每一個處理器都有本身的高速緩存,而它們又共享同一主內存(MainMemory)緩存
Java內存模型規定了全部的變量都存儲在主內存(Main Memory)中(此處的主內存與介紹物理硬件時的主內存名字同樣,二者也能夠互相類比,但此處僅是虛擬機內存的一部分)。每條線程還有本身的工做內存(Working Memory,可與前面講的處理器高速緩存類比),線程的工做內存中保存了被該線程使用到的變量的主內存副本拷貝 ,線程對變量的全部操做(讀取、賦值等)都必須在工做內存中進行,而不能直接讀寫主內存中的變量 。ide
主內存與工做內存之間具體的交互協議,即一個變量如何從主內存拷貝到工做內存、如何從工做內存同步回主內存之類的實現細節,Java內存模型中定義瞭如下8種操做來完成,虛擬機實現時必須保證下面說起的每一種操做都是原子的、不可再分的oop
當一個變量定義爲volatile以後,它將具有兩種特性,第一是保證此變量對全部線程的可見性,這裏的「可見性」是指當一條線程修改了這個變量的值,新值對於其餘線程來講是能夠當即得知的。而普通變量不能作到這一點,普通變量的值在線程間傳遞均須要經過主內存來完成,例如,線程A修改一個普通變量的值,而後向主內存進行回寫,另一條線程B在線程A回寫完成了以後再從主內存進行讀取操做,新變量值纔會對線程B可見。測試
注意這個方法並不能保證原子性,只能保證可見性spa
package test; /** * volatile變量自增運算測試 * */ public class VolatileTest { public static volatile int race = 0; public static void increase() { race++; } private static final int THREADS_COUNT = 20; public static void main(String[] args) { Thread[] threads = new Thread[THREADS_COUNT]; for (int i = 0; i < THREADS_COUNT; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10000; i++) { increase(); } } }); threads[i].start(); } //預期20×10000 // 等待全部累加線程都結束 while (Thread.activeCount() > 1) Thread.yield(); System.out.println(race); } }
預期輸出爲200000實際並非,由於java中運算操做並非原子操做,會有字節碼重排序的狀況發生操作系統
volatile對 long和double型變量的特殊規則線程
Java內存模型要求lock、unlock、read、load、assign、use、store、write這8個操做都具備原子性,可是對於64位的數據類型(long和double),在模型中特別定義了一條相對寬鬆的規定:容許虛擬機將沒有被volatile修飾的64位數據的讀寫操做劃分爲兩次32位的操做來進行,即容許虛擬機實現選擇能夠不保證64位數據類型的load、store、read和write這4個操做的原子性
若是有多個線程共享一個並未聲明爲volatile的long或double類型的變量,而且同時對它們進行讀取和修改操做,那麼某些線程可能會讀取到一個既非原值,也不是其餘線程修改值的表明了「半個變量」的數值3d
注意:目前各類平臺下的商用虛擬機幾乎都選擇把64位數據的讀寫操做做爲原子操做來對待,所以咱們在編寫代碼時通常不須要把用到的long和double變量專門聲明爲volatile
結論:一個操做「時間上的先發生」不表明這個操做會是「先行發生「
對於Sun JDK來講,它的Windows版與Linux版都是使用一對一的線程模型實現的,一條Java線程就映射到一條輕量級進程之中,由於Windows和Linux系統提供的線程模型就是一對一的code
線程調度是指系統爲線程分配處理器使用權的過程,主要調度方式有兩種,分別是協同式線程調度(CooperativeThreads-Scheduling)和搶佔式線程調度(PreemptiveThreads-Scheduling)