如果對共享的可變資料的存取不能同步,其後果非常可怕,即使這個變數是原子可讀寫的。
下面考慮一個線程同步方面的問題。對於執行緒同步,Java類別函式庫提供了Thread.stop的方法,但這個方法並不值得提倡,因為它本質上是不安全的。使用輪詢(Polling)的方式會更好,例如下面這段程式。
複製代碼代碼如下:
import java.util.concurrent.TimeUnit;
public class StopThread {
/**
* @param args
*/
private static boolean stopRequested;
public static void main(String[] args)
throws InterruptedException{
Thread backgroundThread = new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while(!stopRequested){
i++;
System.out.println(i);
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
你可能會認為這個程式在運行大約一秒後,由於主線程把stopRequested設成了true,使得後台的新線程停止,其實不然,因為後台線程看不到這個值的變化,所以會一直無線循環下去,這就是沒有對資料進行同步的後果。因此讓我們用同步的方式來實現這個任務。
複製代碼代碼如下:
import java.util.concurrent.TimeUnit;
public class StopThread {
/**
* @param args
*/
private static boolean stopRequested;
private static synchronized void requestStop(){
stopRequested = true;
}
private static synchronized boolean stopRequested(){
return stopRequested;
}
public static void main(String[] args)
throws InterruptedException{
Thread backgroundThread = new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while(!stopRequested()){
i++;
System.out.println(i);
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
這樣就實現了資料的同步,值得注意的是,寫入方法(requestStop)和讀取方法(stopRequested)都需要被同步,否則仍然不是真正意義上的同步。
另外,我們可以使用volatile這個變數修飾符來更簡單地完成同步任務。
複製代碼代碼如下:
import java.util.concurrent.TimeUnit;
public class StopThread {
/**
* @param args
*/
private static volatile boolean stopRequested;
public static void main(String[] args)
throws InterruptedException{
Thread backgroundThread = new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while(!stopRequested){
i++;
System.out.println(i);
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}