1. 程式人生 > >Java多執行緒基礎之資料共享引發的“非執行緒安全”

Java多執行緒基礎之資料共享引發的“非執行緒安全”

例項變數與執行緒安全

     自定義執行緒類中的例項變數針對其他執行緒可以有共享與不共享之分,這在多個執行緒之間進行互動時是很重要的一個技術點。

    一 、不共享資料的情況

       

public class MyThread extends Thread {
	
	private int count = 5 ;
	
	
	 public MyThread(String name) {
		 super();
		 this.setName(name);
		 
	}

	@Override
	public void run() {
		super.run();
		while (count > 0) {
			count--;
			System.out.println("由 " + this.currentThread().getName() + " 計算,count=" + count);
			
		}
	
	}

}
public class Run {
	
	public static void main(String[] args) {

			
			
			MyThread a = new MyThread("A");
			MyThread b = new MyThread("B");
			MyThread c = new MyThread("C");
			a.start();
			b.start();
			c.start();

	}
}

以上可以看出,一共建立3個執行緒,每個執行緒都有各自的count變數,自己減少自己的count變數的值,也就是變數不共享的情況

 

  二 、不共享資料的情況

public class MyThread extends Thread {
	
	private int count = 5 ;
	
	@Override
	public void run() {
		super.run();
			count--;
			System.out.println("由 " + this.currentThread().getName() + " 計算,count=" + count);
	}
}
public class Run {
	
	public static void main(String[] args) {

			
			
			MyThread myThread = new MyThread();
			Thread a = new Thread(myThread,"A");
			Thread b = new Thread(myThread,"B");
			Thread c= new Thread(myThread,"C");
			Thread d = new Thread(myThread,"D");
			Thread e = new Thread(myThread,"E");
			a.start();
			b.start();
			c.start();
			d.start();
			e.start();

	}
}

 

 發現3有兩個執行緒同時列印,我們想要看的結果沒有重複的,而是依次遞減的,從而發生了非執行緒安全的問題。

其實在JVM中,i -- 的操作是分為3步的

  1. 取得原有的i 值;
  2. 計算i-1;
  3. 對i 進行賦值

如果有多個執行緒同時訪問自然出現非執行緒安全問題。在上面的MyThread類 的run方法中加個關鍵字synchronized。再試試

 

public class MyThread extends Thread {
	
	private int count = 5 ;
	
	@Override
	synchronized  public void run() {
		super.run();
			count--;
			System.out.println("由 " + this.currentThread().getName() + " 計算,count=" + count);
	}
}

執行緒已經安全了。

 

synchronized可以在任意物件及方法上加鎖,而加鎖的這段程式碼稱為“互斥區”或者“臨界區”。加上它的作用其實就是給方法上了鎖,當一個執行緒執行這個方法時,其實就是得到了這把鎖,其他執行緒就不會進來,等拿到鎖的這個執行緒執行完了,其他執行緒才會搶這把鎖,當然也包括前面那個已經執行完的執行緒。