synchronized和volatile解決線程可見性

java多線程開發中,控制共享數據比較麻煩,有可見性和同步性。通常控制可見性咱們能夠經過synchronized和volatile控制,而同步性咱們只能經過synchronized或Lock來控制。java

我喜歡經過對一個問題的理解,來理解某個知識點,由於我以爲知識就是爲了解決問題。多線程

public class SynchronizedTest {
	
	private static boolean flag = true;
	

	public static void main(String[] args) throws Exception{

		new Thread(new Runnable() {
			@Override
			public void run() {
				while(flag) {
					
				}
				System.out.println("子線程執行結束================");
			}
		}).start();
		
		Thread.sleep(1000);
		
		flag = false; // 關閉線程輸出
		System.out.println("flag已被修改成false");
	}

}

上面的代碼在64位JVM機器(準確來講應該是jvm的server模式)上執行通常都不會輸出「子線程執行結束================」,而在32位的jvm的client模式下卻能夠輸出「子線程執行結束================」。jvm

經過 java -version 能夠查看本身本機jvm運行的模式。ide

注意:若是你的jvm裝的是64位,那麼是沒法切換到client模式的。優化

上面的問題引發的緣由其實就是因爲java的內存模型引發的,java內存模型中分有主內存和工做內存之分,主內存能夠理解爲共享數據的區域(不知道準確不許確),而工做內存(主內存數據的副本)是每一個線程私有的一塊區域,每一個線程對共享數據的修改,不會直接操做共享數據,通常是先修改工做內存中的數據,而後在某個特定的時候刷新到主存,其餘線程纔有機會看到其修改。this

解決以上問題線程

  1. 能夠將flag前加上volatile關鍵字。

private static volatile boolean flag = true;code

緣由:能夠這麼簡單理解,加了volatile關鍵字的共享變量,全部線程對其值的獲取或修改都直接經過主存,繞過來工做內存,因此主線程對flag的修改子線程立刻就能夠看到。server

volatile的原理就是加內存屏障,全部的讀都在寫以後,這樣保證了子線程對flag的訪問在主線程對flag的修改以後。對象

  1. 可使用synchronized
new Thread(new Runnable() {
	@Override
	public void run() {
		int count = 0;
		while(flag) {
			synchronized(SynchronizedTest.class){ //這裏能夠鎖任何共享對象
				count++;
			}		
		}
		System.out.println("子線程執行結束================");
	}
}).start();

上面之因此加上 count ,是防止JIT優化將無用的鎖代碼塊優化掉。

緣由:因爲jvm規定在進入synchronized以前會將全部其餘線程的工做內存刷新到主存(這個我不太肯定是否正確,若是有肯定的請留言告訴我,謝謝),在離開synchronized塊以前會將本線程的工做內存刷新到主內存。

在驗證這個之中我踩過一個坑,個人代碼以下:

new Thread(new Runnable() {
	@Override
	public void run() {
		while(flag) {
			System.out.println("====falg=====");	
		}
		System.out.println("子線程執行結束================");
	}
}).start();

這樣在任何狀況下均可以輸出"子線程執行結束================",找了好久才發現原來 System.out.println 方法中有synchronized同步塊致使。

這個方法來自 System.out

public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }

之中有很多觀點是我本身的觀點,可能不許確,或是錯誤的,但願大家能給我指出,謝謝。

相關文章
相關標籤/搜索