Java併發之原子性,有序性,可見性,以及Happen-Before原則

原子性

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

例如 i++,其實經歷了讀,算,賦值絕對算不上是一個原子操做。一個i = 10這樣的賦值操做能夠稱爲原子操做。緩存

java.util.comcurrent.atomic包裏都是關於原子操做的類,有時間會另寫一篇博客。安全

有序性

提到有序那必然就有亂序,而亂序是由於jvm的指令重排優化而產生的。app

咱們要想徹底保住有序性,須要給對象加同步鎖(synchronized),這樣作實際上就是單線程執行了。jvm

可見性

可見性是指當一個線程修改了某一個共享變量的值,其餘線程是否可以當即知道這個修改。 函數

而其餘線程看不到其實是由於每一個cpu都有寄存器,有一個線程把寄存器裏的值修改了並提交到jvm了,而還有一個cpu的寄存器裏存着數據的緩存,等它回頭看jvm的時候,發現值已經變了。oop

Java提供了volatile關鍵字來保證可見性。測試

當一個共享變量被volatile修飾時,它會保證修改的值會當即被更新到主存,當有其餘線程須要讀取時,它會去內存中讀取新值。優化

下面用一段代碼來作測試。atom

public class VisibilityTest extends Thread{
  //若是沒有關鍵字volatile,會發現這個線程停不掉,可自行測試。
private volatile boolean stop; public void run() { int i = 0; while (!stop) { i++; } System.out.println("finish loop,i=" + i); } public void stopIt() { stop = true; } public boolean getStop() { return stop; } public static void main(String[] args) throws InterruptedException { VisibilityTest visibilityTest = new VisibilityTest(); visibilityTest.start(); visibilityTest.sleep(1000); visibilityTest.stopIt(); System.out.println(visibilityTest.getStop()); } }

除了volatile還有兩種解決可見性問題的方法:

1. final關鍵字,可以解決的緣由:final常量會進常量區(之前的方法區,如今的Metaspace),常量區是線程安全的,線程安全就是一個線程佔有着此資源的時候,其餘線程不能佔有,因此可想而知,只要A線程在對此資源作任何操做,B線程都是等待着的,當A釋放了,B纔去jvm拿值,這樣也算保證了可見性。

2. synchronized關鍵字,緣由和上面同樣,同步鎖,保證了線程安全。

Happen-Before原則

 程序順序原則:一個線程內保證語義的串行性 a=1 b=a+1

 volatile規則:volatile變量的寫,先發生於讀,這保證了volatile變量的可見性

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

 傳遞性:A先於B,B先於C,那麼A必然先於C

 線程的start()方法先於它的每個動做  線程的全部操做先於線程的終結(Thread.join())

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

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

相關文章
相關標籤/搜索