[java]volatile關鍵字作用和用法

一,volatile關鍵字的作用

  • 保持多個線程對共享數據操作內存的可見性
  • 禁止指令重排序

二,什麼是內存可見性?

1.爲什麼會產生內存不可見性?

在硬件通過cache來提高訪存的效率

  • 在學習計算機組成原理中我們曾瞭解過主存和高速緩存cache,爲了解決CPU速度和主存速度不匹配。於是產生了高速緩衝存儲器cache。

  • CPU和cache的數據交換:當CPU讀取內存中的一個字時,便發出此字的內存地址到cache和主存。此時通過邏輯依據地址判斷此字當前是否在cache中:若是,此字立即傳送給CPU,若非,則用主存讀週期把此字從主存送到CPU,與此同時,把含有這個字的整個數據塊從主存讀出送到cache中。這樣大大縮短了讀取數據的時間。

jvm通過備份主存的數據來提高訪存的效率

  • 我們知道,操作主存速度很慢。當我們有多個線程同時操作主存時,降低了程序的執行速度。
  • jvm會爲每個線程分配一個區域,用來備份主存中的數據。每個線程通過操作自己區域中的數據,操作完成後,只需要刷新到主存即可。這樣就引發了多線程操作共享數據的內存不可見性!

三,保持內存可見性的辦法

可以當之無愧的被稱爲Java併發編程中“出現頻率最高的關鍵字”volatitle,常用於保持內存可見性和防止指令重排序。

  • 下面是一個例程:
/**
 * 測試多線程操作共享數據的內存不可見性
 * @author 91681
 *
 */
public class VolatileDemo1 {
	
	
	public static void main(String[] args) {
		Resource r = new Resource();
		new Thread(r).start();
		while(true){
			if(r.isFlag()){
				System.out.println("退出循環");
				break;
			}
		}
	
	}
}
class Resource implements Runnable{
	private boolean flag = false;
	public void run(){
		flag = true;
		System.out.println("flag="+flag);
	}
	public boolean isFlag() {
		return flag;
	}
	public void setFlag(boolean flag) {
		this.flag = flag;
	}
}

我們運行程序奇怪的發現程序沒有停止運行!!!分析原因。。。在這裏插入圖片描述
當我們加上volatile關鍵字後,程序正常退出。
爲什麼:加上volatile關鍵字後,在線程空間中修改或讀取主存中的共享數據時,其實就像在主存中讀取或修改一樣。每次進行操作後,都會進行刷新副本到主存。

四,volatile的優勢

相比較synchronize是一個輕量級的控制併發的組件,系統開銷比較小

四,volatile的侷限性

  • 不能解決互斥問題
    volatile只能保證線程中的共享數據是實時的,線程的互斥問題還得用synchronize或semarphone

  • 不能保證對它修飾的變量具有原子性
    首先需要了解的是,Java中只有對基本類型變量的賦值和讀取是原子操作,如i = 1的賦值操作,但是像j = i或者i++這樣的操作都不是原子操作,因爲他們都進行了多次原子操作,比如先讀取i的值,再將i的值賦值給j,兩個原子操作加起來就不是原子操作了。

    所以,如果一個變量被volatile修飾了,那麼肯定可以保證每次讀取這個變量值的時候得到的值是最新的,但是一旦需要對變量進行自增這樣的非原子操作,就不會保證這個變量的原子性了。

    舉個栗子

    一個變量i被volatile修飾,兩個線程想對這個變量修改,都對其進行自增操作也就是i++,i++的過程可以分爲三步,首先獲取i的值,其次對i的值進行加1,最後將得到的新值寫會到緩存中。
    線程A首先得到了i的初始值100,但是還沒來得及修改,就阻塞了,這時線程B開始了,它也得到了i的值,由於i的值未被修改,即使是被volatile修飾,主存的變量還沒變化,那麼線程B得到的值也是100,之後對其進行加1操作,得到101後,將新值寫入到緩存中,再刷入主存中。根據可見性的原則,這個主存的值可以被其他線程可見。
    問題來了,線程A已經讀取到了i的值爲100,也就是說讀取的這個原子操作已經結束了,所以這個可見性來的有點晚,線程A阻塞結束後,繼續將100這個值加1,得到101,再將值寫到緩存,最後刷入主存,所以即便是volatile具有可見性,也不能保證對它修飾的變量具有原子性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章