天天看點

【java】【多線程】線程安全與線程非安全【1】

線程安全與線程非安全,怎樣區分呢?

其實,當線程通路同一資源時,如同一個對象的同一個變量,會存在多個線程對同一資源的競争通路,也就存線上程非安全。是以說,非安全指的是:多個線程通路同一個資源,可能會通路到非想要的資源。如線程一改寫了變量a,而線程二此時又來通路變量a,則線程二得到的是修改後的變量a,而不是修改前的變量a。這樣,就存在了資料的非安全通路,稱之為線程非安全。這也可以稱為資料的髒讀。

反之,如果兩個線程不會通路同樣的資源,則不會存在上述問題,是以,稱之為線程安全。

那是不是隻要;兩個線程通路同一對象的同一資源就是線程不安全的呢?

這也不是。如果通路的是同一個方法,而該方法有沒有通路類的其他屬性,則該方法的通路不存線上程安全問題。即:方法内部的局部變量是線程安全的。

代碼如下:

package com.cmm.thread1;

public class ThreadSafe {
	
	public void add(int a) throws InterruptedException{
		int num = 0;
		if(a == 100){
			num = 100;
			Thread.sleep(1000);
			System.out.println("num = " + num);
		}else{
			num = 200;
			System.out.println("num = " + num);
		}
	}
}
           
package com.cmm.thread1;

public class ThreadA extends Thread{
	private ThreadSafe safe;
	public ThreadA(ThreadSafe safe) {
		this.safe = safe;
	}
	@Override
	public void run() {
		super.run();
		try {
			this.safe.add(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
           
package com.cmm.thread1;

public class ThreadB extends Thread{
	private ThreadSafe safe;
	public ThreadB(ThreadSafe safe) {
		this.safe = safe;
	}
	@Override
	public void run() {
		super.run();
		try {
			this.safe.add(200);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}
           

測試代碼如下:

package com.cmm.thread1;

public class Main {
	public static void main(String[] args) {
		ThreadSafe safe = new ThreadSafe();
		
		ThreadA threadA = new ThreadA(safe);
		
		ThreadB threadB = new ThreadB(safe);
		
		threadA.start();
		threadB.start();
		
	}
}
           

多次測試結果為:

num = 200

num = 100

可以看出,多個線程通路同一方法的局部變量是線程安全的。

但是,如果是類的屬性,則存線上程不安全的問題。

修改代碼如下:

package com.cmm.thread1;

public class ThreadSafe {
	private int num = 0;
	public void add(int a) throws InterruptedException{
		
		if(a == 100){
			num = 100;
			Thread.sleep(1000);
			System.out.println("num = " + num);
		}else{
			num = 200;
			System.out.println("num = " + num);
		}
	}
}
           

測試結果如下:

num = 200

num = 200

可以看出,出現的資料髒讀。

當多線程通路同一資源時,就會出現髒讀問題。是以,這個時候,需要用一定的手段,來使得同一時刻,隻有一個線程可以對共享資源進行通路。通路分兩種,隻讀,讀寫。是以又有不同的處理。

後面,會詳細介紹線程同步問題。

在這裡先總結一句話:線程同步問題,就是為了解決多個線程對共享資料的同時通路問題,通路又分為隻讀與讀寫兩種,是以,線程同步,需要分場景做不同的讨論處理。