線程安全與線程非安全,怎樣區分呢?
其實,當線程通路同一資源時,如同一個對象的同一個變量,會存在多個線程對同一資源的競争通路,也就存線上程非安全。是以說,非安全指的是:多個線程通路同一個資源,可能會通路到非想要的資源。如線程一改寫了變量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
可以看出,出現的資料髒讀。
當多線程通路同一資源時,就會出現髒讀問題。是以,這個時候,需要用一定的手段,來使得同一時刻,隻有一個線程可以對共享資源進行通路。通路分兩種,隻讀,讀寫。是以又有不同的處理。
後面,會詳細介紹線程同步問題。
在這裡先總結一句話:線程同步問題,就是為了解決多個線程對共享資料的同時通路問題,通路又分為隻讀與讀寫兩種,是以,線程同步,需要分場景做不同的讨論處理。