- 通過共享對象通信
線程間發(fā)送信號的一個簡單方式是在共享對象的變量里設置信號值系宜。 - 忙等待(Busy Wait)
準備處理數(shù)據的線程B正在等待數(shù)據變?yōu)榭捎迷烁摇Q句話說拄查,它在等待線程A的一個信號 - wait(),notify()和notifyAll()
忙等待沒有對運行等待線程的CPU進行有效的利用躺彬,除非平均等待時間非常短咕痛。否則,讓等待線程進入睡眠或者非運行狀態(tài)更為明智油挥,直到它接收到它等待的信號潦蝇。
Java有一個內建的等待機制來允許線程在等待信號的時候變?yōu)榉沁\行狀態(tài)。java.lang.Object 類定義了三個方法深寥,wait()攘乒、notify()和notifyAll()來實現(xiàn)這個等待機制。 - 丟失的信號(Missed Signals)
notify()和notifyAll()方法不會保存調用它們的方法惋鹅,因為當這兩個方法被調用時则酝,有可能沒有線程處于等待狀態(tài)。通知信號過后便丟棄了闰集。因此沽讹,如果一個線程先于被通知線程調用wait()前調用了notify(),等待的線程將錯過這個信號武鲁。這可能是也可能不是個問題爽雄。不過,在某些情況下沐鼠,這可能使等待線程永遠在等待挚瘟,不再醒來,因為線程錯過了喚醒信號饲梭。 - 假喚醒
為了防止假喚醒乘盖,保存信號的成員變量將在一個while循環(huán)里接受檢查,而不是在if表達式里憔涉。這樣的一個while循環(huán)叫做自旋鎖订框。 - 多個線程等待相同信號
- 不要在字符串常量或全局對象中調用wait()
所以:在wait()/notify()機制中,不要使用全局對象兜叨,字符串常量等穿扳。應該使用對應唯一的對象。
● 靜態(tài)變量:線程非安全国旷。
靜態(tài)變量即類變量矛物,位于方法區(qū),為所有對象共享议街,共享一份內存,一旦靜態(tài)變量被修改璧榄,其他對象均對修改可見特漩,故線程非安全吧雹。
● 實例變量:單例模式(只有一個對象實例存在)線程非安全,非單例線程安全涂身。
實例變量為對象實例私有雄卷,在虛擬機的堆中分配,若在系統(tǒng)中只存在一個此對象的實例蛤售,在多線程環(huán)境下丁鹉,“猶如”靜態(tài)變量那樣,被某個線程修改后悴能,其他線程對修改均可見揣钦,故線程非安全;如果每個線程執(zhí)行都是在不同的對象中漠酿,那對象與對象之間的實例變量的修改將互不影響冯凹,故線程安全。
● 局部變量:線程安全炒嘲。
每個線程執(zhí)行時將會把局部變量放在各自棧幀的工作內存中宇姚,線程間不共享,故不存在線程安全問題夫凸。
public class ThreadShareData {
private static int data=0;
private static Map<Thread,Integer> threadData=new HashMap<Thread,Integer>();
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
data = new Random().nextInt() ;
System.out.println(Thread.currentThread().getName() + ":" + data);
threadData.put(Thread.currentThread(),data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
data=threadData.get(Thread.currentThread());
System.out.println("A--"+Thread.currentThread().getName()+":"+data);
}
}
static class B{
public void get(){
data=threadData.get(Thread.currentThread());
System.out.println("B--"+Thread.currentThread().getName()+":"+data);
}
}
}
輸出結果:
Thread-1:308764307
Thread-0:499909925
A--Thread-1:499909925
A--Thread-0:499909925
B--Thread-0:499909925
B--Thread-1:499909925
private static int data=0;
private static Map<Thread,Integer> threadData=new HashMap<Thread,Integer>();
threadData是一個HashMap浑劳,同一個線程只能放一個data。