volatile關鍵字 線程可見性

一、概念
  在java中,每一個線程都會有自己的工作內存區域,在主內存中對共享變量值進行拷貝,形成副本,放在每個線程獨自的內存區域。當各自的線程運行時,會在自己的內存區域操作這些變量的值,爲了存取一個共享的變量,一個線程通常獲鎖定並且清除自己的內存工作區,把這些共享變量的值從所有線程共享內存區域中正確的裝入到自己的工作內存區域,當線程解鎖時,把工作區域的變量值刷新到主內存中的共享變量中。
   一個線程可以使用的操作有使用(use),賦值(assign),裝載(load),存儲(store),鎖定(lock),解鎖(unlock)
   主內存可以執行的操作有:讀(read),寫(write),鎖定(lock),解鎖(unlock)
   volatile關鍵字的作用就是強制到主內存(共享內存)裏去讀取變量,而不是去線程工作區去讀,從而實現了多線程間的變量可見,滿足線程安全的可見性。當某個線程對共享變量進行更改的時候,線程引擎會強制讓引用了共享變量的線程去共享變量中讀取值。
   volatile不具備原子性,如果要要保證原子性,建議使用automic系列對象(只保證本身原子性,並不保證多次操作的原子性)

/**
 * volatile關鍵字不具備synchronized關鍵字的原子性(同步)
 *
 */
public class VolatileNoAtomic extends Thread{
	//private static volatile int count;
	private static AtomicInteger count = new AtomicInteger(0);
	private static void addCount(){
		for (int i = 0; i < 1000; i++) {
			//count++ ;
			count.incrementAndGet();
		}
		System.out.println(count);
	}
	
	public void run(){
		addCount();
	}
	
	public static void main(String[] args) {
		
		VolatileNoAtomic[] arr = new VolatileNoAtomic[100];
		for (int i = 0; i < 10; i++) {
			arr[i] = new VolatileNoAtomic();
		}
		
		for (int i = 0; i < 10; i++) {
			arr[i].start();
		}
	}

public class AtomicUse {

	private static AtomicInteger count = new AtomicInteger(0);
	
	//多個addAndGet在一個方法內是非原子性的,需要加synchronized進行修飾,保證4個addAndGet整體原子性
	/**synchronized*/
	public synchronized int multiAdd(){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			count.addAndGet(1);
			count.addAndGet(2);
			count.addAndGet(3);
			count.addAndGet(4); //+10
			return count.get();
	}
	
	
	public static void main(String[] args) {
		
		final AtomicUse au = new AtomicUse();

		List<Thread> ts = new ArrayList<Thread>();
		for (int i = 0; i < 100; i++) {
			ts.add(new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(au.multiAdd());
				}
			}));
		}

		for(Thread t : ts){
			t.start();
		}
		
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章