Java內存模型

概述java

在併發編程中,須要處理兩個關鍵問題:線程之間如何通訊,以及線程之間如何同步。通訊是指線程之間如何交換信息,在命令式編程中,線程之間的通訊機制有兩種:內存共享和消息傳遞。程序員

同步是指程序中用於控制不一樣線程間的操做發生相對順序的機制。在共享內存併發模型中,同步是顯性進行的。程序員須要顯性設置某段代碼在線程之間的互斥執行。在消息傳遞的併發模型中,因爲消息的發送必須在消息的接受以前,所以同步是隱性進行的。編程

Java併發採用的是共享內存模型。微信

Java內存模型(JMM)的關鍵技術點都是圍繞着多線程的原子性、有序性、可見性來創建的。多線程

1. 原子性-Atomicity併發

原子性是指一個操做是不可中斷的。即便在多個線程一塊兒執行的時候,一個操做一旦開始,就不會被其餘線程干擾。app

例如,對於一個靜態變量i,有兩個線程對其賦值,線程A給它賦值1,線程B給它賦值2,那麼無論這兩個線程如何工做,i要麼是1,要麼是2。線程A和B之間是沒有干擾的,這就是原子性的一個特色,不可被中斷。函數

可是若是使用long類型(long類型是64位)的話,對於32位操做系統而言,long型數據的讀寫不是原子操做,也就是說,多個線程同時對一個long進行操做的話,線程之間的結果是有干擾的。優化

2. 可見性-Visibility操作系統

可見性是指當一個線程修改了一個共享變量的值,其餘線程是否可以當即知道這個修改。對於串行程序來講,這個問題是不存在的,由於在任何一個步驟中修改了變量值,在後續的步驟中讀取這個值,必定是修改後的。

可是在並行程序中就不見得了。若是一個線程修改了變量值,其餘線程未必能立刻知道這個改動。A線程和線程B分別讀取了變量i,A再對變量i操做,這時候B是不必定能立刻知道的。

3. 有序性-Ordering

對於一個線程的執行代碼而言,咱們老是習慣性的認爲代碼的執行是從前日後依次執行的。可是在併發時,程序的執行就可能出現亂序。給人的直觀感覺就是:後面的代碼先執行,前面的代碼後執行。聽起來很難以想象,這是因爲程序在執行時,可能會進行指令重排,即在不影響串行語義的狀況下對指令的順序進行調整,以優化CPU的執行效率(指令重排能夠保證串行語義一致,但沒有辦法保證多線程間的語義也一致)。關於指令重排,後面抽空再寫專門的文章來講明。

雖然java虛擬機和執行系統會對指令進行重排,可是仍是有一些原則是指令重排不能違背的,即Happen-Before規則:

  • 程序順序原則:一個線程內保證語義的串行性

  • volatile規則:volatile變量的寫,先發生於讀,這保證了volatile變量的可見性(抽空寫一篇關於volatile的介紹)

  • 鎖規則:解鎖(unlock)必然發生在隨後的加鎖(lock)前

  • 傳遞性:A先於B,B先於C,則A必然先於C

  • 線程的start()方法先於它的每個動做

  • 線程的全部操做先於線程的終結(Thread.join())

  • 線程的中斷(interrupt())先於被中斷線程的代碼

  • 對象的構造函數執行、結束先於finalize()方法


歡迎關注微信公衆號:程序員順仔

相關文章
相關標籤/搜索