在Java語言中,採用的是共享內存模型來實現多線程之間的信息交換和數據同步的。程序員
線程之間經過共享程序公共的狀態,經過讀-寫內存中公共狀態的方式來進行隱式的通訊。同步指的是程序在控制多個線程之間執行程序的相對順序的機制,在共享內存模型中,同步是顯式的,程序員必須顯式指定某個方法/代碼塊須要在多線程之間互斥執行。算法
在說Java內存模型以前,咱們先說一下Java的內存結構,也就是運行時的數據區域:數組
Java虛擬機在執行Java程序的過程當中,會把它管理的內存劃分爲幾個不一樣的數據區域,這些區域都有各自的用途、建立時間、銷燬時間。安全
嚴格來講是一個數據結構,用於保存當前正在執行的程序的內存地址,因爲Java是支持多線程執行的,因此程序執行的軌跡不可能一直都是線性執行。當有多個線程交叉執行時,被中斷的線程的程序當前執行到哪條內存地址必然要保存下來,以便用於被中斷的線程恢復執行時再按照被中斷時的指令地址繼續執行下去。爲了線程切換後能恢復到正確的執行位置,每一個線程都須要有一個獨立的程序計數器,各個線程之間計數器互不影響,獨立存儲,咱們稱這類內存區域爲「線程私有」的內存,這在某種程度上有點相似於「ThreadLocal」,是線程安全的。數據結構
Java棧老是與線程關聯在一塊兒的,每當建立一個線程,JVM就會爲該線程建立對應的Java棧,在這個Java棧中又會包含多個棧幀(Stack Frame),這些棧幀是與每一個方法關聯起來的,每運行一個方法就建立一個棧幀,每一個棧幀會含有一些局部變量、操做棧和方法返回值等信息。每當一個方法執行完成時,該棧幀就會彈出棧幀的元素做爲這個方法的返回值,而且清除這個棧幀,Java棧的棧頂的棧幀就是當前正在執行的活動棧,也就是當前正在執行的方法,PC寄存器也會指向該地址。只有這個活動的棧幀的本地變量能夠被操做棧使用,當在這個棧幀中調用另一個方法時,與之對應的一個新的棧幀被建立,這個新建立的棧幀被放到Java棧的棧頂,變爲當前的活動棧。一樣如今只有這個棧的本地變量才能被使用,當這個棧幀中全部指令都完成時,這個棧幀被移除Java棧,剛纔的那個棧幀變爲活動棧幀,前面棧幀的返回值變爲這個棧幀的操做棧的一個操做數。多線程
因爲Java棧是與線程對應起來的,Java棧數據不是線程共有的,因此不須要關心其數據一致性,也不會存在同步鎖的問題。函數
在Java虛擬機規範中,對這個區域規定了兩種異常情況:若是線程請求的棧深度大於虛擬機所容許的深度,將拋出StackOverflowError異常;若是虛擬機能夠動態擴展,若是擴展時沒法申請到足夠的內存,就會拋出OutOfMemoryError異常。在Hot Spot虛擬機中,可使用-Xss參數來設置棧的大小。棧的大小直接決定了函數調用的可達深度。spa
堆是JVM所管理的內存中國最大的一塊,是被全部Java線程鎖共享的,不是線程安全的,在JVM啓動時建立。堆是存儲Java對象的地方,這一點Java虛擬機規範中描述是:全部的對象實例以及數組都要在堆上分配。Java堆是GC管理的主要區域,從內存回收的角度來看,因爲如今GC基本都採用分代收集算法,因此Java堆還能夠細分爲:新生代和老年代;新生代再細緻一點有Eden空間、From Survivor空間、To Survivor空間等。線程
方法區存放了要加載的類的信息(名稱、修飾符等)、類中的靜態常量、類中定義爲final類型的常量、類中的Field信息、類中的方法信息,當在程序中經過Class對象的getName.isInterface等方法來獲取信息時,這些數據都來源於方法區。方法區是被Java線程鎖共享的,不像Java堆中其餘部分同樣會頻繁被GC回收,它存儲的信息相對比較穩定,在必定條件下會被GC,當方法區要使用的內存超過其容許的大小時,會拋出OutOfMemory的錯誤信息。方法區也是堆中的一部分,就是咱們一般所說的Java堆中的永久區 Permanet Generation,大小能夠經過參數來設置,能夠經過-XX:PermSize指定初始值,-XX:MaxPermSize指定最大值。3d
常量池自己是方法區中的一個數據結構。常量池中存儲瞭如字符串、final變量值、類名和方法名常量。常量池在編譯期間就被肯定,並保存在已編譯的.class文件中。通常分爲兩類:字面量和應用量。字面量就是字符串、final變量等。類名和方法名屬於引用量。引用量最多見的是在調用方法的時候,根據方法名找到方法的引用,並以此定爲到函數體進行函數代碼的執行。引用量包含:類和接口的權限定名、字段的名稱和描述符,方法的名稱和描述符。
本地方法棧和Java棧所發揮的做用很是類似,區別不過是Java棧爲JVM執行Java方法服務,而本地方法棧爲JVM執行Native方法服務。本地方法棧也會拋出StackOverflowError和OutOfMemoryError異常。
未完待續