概述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()方法
歡迎關注微信公衆號:程序員順仔