在多線程中存在可見性問題,詳見 java-多線程深入(二)互斥性和可見性,可見性遵循happens-before規則。
(一)happens-before規則
happens-before規則:若A happens-before B,則操作A中的影響都能被B知道,影響包括修改主內存中共享變量值、發送消息、調用方法等。
java內存模型中的八成happens-before規則:
1、程序次序規則:單線程中,按照程序代碼,前面的操作happens-before後面的操作。
2、鎖定規則:對於同一個鎖,unlock的操作happens-before lock的操作。
3、volatile變量規則:對volatile變量寫操作happens-before讀操作。
4、傳遞性:如果操作A happens—before操作B,操作B happens—before操作C,那麼可以得出A happens—before操作C。
5、線程啓動規則:Thread對象的start方法happens—before此線程的每一個動作。
6、線程終止規則:線程的所有操作都happens—before對此線程的終止檢測,可以通過Thread.join()方法結束、Thread.isAlive()的返回值等手段檢測到線程已經終止執行。
7、線程中斷規則:對線程interrupt方法的調用happens—before發生於被中斷線程的代碼檢測到中斷時事件的發生。
8、對象終結規則:一個對象的初始化完成(構造函數執行結束)happens—before它的finalize方法的開始。
(二)tb和hb的關係
tb(time-before)和hb(happens-before)沒有直接的關係。tb指按照程序執行情況,操作在前的tb操作在後的。
1、tb不代表hb
/**
* 多線程可見性測試
*
* @author peter_wang
* @create-time 2015-1-12 下午3:56:29
*/
public class ThreadVisableDemo {
private static int a = 0;
static class GetNumThread
extends Thread {
@Override
public void run() {
System.out.println(a);//B1
}
}
static class ChangeNumThread
extends Thread {
@Override
public void run() {
a = 1;//A1,A2
}
}
/**
* @param args
*/
public static void main(String[] args) {
GetNumThread getNumThread = new GetNumThread();
ChangeNumThread changeNumThread = new ChangeNumThread();
changeNumThread.start();//C1
getNumThread.start();//C2
}
}
C1先於C2執行,存在C1 tb C2關係,但由上一篇博文可知,a不存在可見性,執行A1完數據不一定會及時刷新,B1最終輸出可爲0或1,C1 hb C2不存在。
2.hb不代表tb
a = 1; //A1
b = 2; //A2
按照規則1,A1 hb A2,因爲兩段代碼沒存在數據關聯(A1和A2互換不會影響運行結果),JVM自動優化性能,可能存在編譯代碼重排序或執行指令代碼重排序問題,所以可能存在A2 tb A1。