這是對在 multi-thread 中 static field 同步化的紀錄。
以下是 TestThread,在 run 函式結束後,我們希望 mNumber 不會成為負數。
重點放在第3行的 mNumber 。目前它不是 static field。
public class TestThread extends Thread
{
private int mNumber = 100;
public void run()
{
while (mNumber >= 10) {
delayRandomMillSeconds();
mNumber -= 10;
System.out.println("thread name:"+getName()+" in while number:"+mNumber);
}
System.out.println("thread name:"+getName()+" final number:"+mNumber);
}
private void delayRandomMillSeconds()
{
try {
Thread.sleep(new Random().nextInt(500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在非共享呼叫的情況(個別產生實體)下,mNumber不會成為負數。
private static void runWithoutSharedResource()
{
new TestThread().start();
new TestThread().start();
new TestThread().start();
}
Output:
thread name:Thread-2 in while number:90 thread name:Thread-0 in while number:90 thread name:Thread-1 in while number:90 thread name:Thread-2 in while number:80 thread name:Thread-1 in while number:80 thread name:Thread-0 in while number:80 thread name:Thread-0 in while number:70 thread name:Thread-1 in while number:70 thread name:Thread-2 in while number:70 thread name:Thread-2 in while number:60 thread name:Thread-2 in while number:50 thread name:Thread-2 in while number:40 thread name:Thread-0 in while number:60 thread name:Thread-0 in while number:50 thread name:Thread-1 in while number:60 thread name:Thread-1 in while number:50 thread name:Thread-2 in while number:30 thread name:Thread-0 in while number:40 thread name:Thread-1 in while number:40 thread name:Thread-2 in while number:20 thread name:Thread-0 in while number:30 thread name:Thread-2 in while number:10 thread name:Thread-1 in while number:30 thread name:Thread-0 in while number:20 thread name:Thread-2 in while number:0 thread name:Thread-2 final number:0 thread name:Thread-1 in while number:20 thread name:Thread-0 in while number:10 thread name:Thread-0 in while number:0 thread name:Thread-0 final number:0 thread name:Thread-1 in while number:10 thread name:Thread-1 in while number:0 thread name:Thread-1 final number:0
但若把 mNumber 改為 static 。
public class TestThread extends Thread
{
private static int mNumber = 100;
public void run()
{
while (mNumber >= 10) {
delayRandomMillSeconds();
mNumber -= 10;
System.out.println("thread name:"+getName()+" in while number:"+mNumber);
}
System.out.println("thread name:"+getName()+" final number:"+mNumber);
}
private void delayRandomMillSeconds()
{
try {
Thread.sleep(new Random().nextInt(500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
這時候 mNumber 就成為共享資源(Shared Resource)。
一樣的呼叫方式(個別產生實體)
private static void runWithoutSharedResource()
{
new TestThread().start();
new TestThread().start();
new TestThread().start();
}
output:
thread name:Thread-2 in while number:90 thread name:Thread-0 in while number:80 thread name:Thread-1 in while number:70 thread name:Thread-0 in while number:60 thread name:Thread-2 in while number:50 thread name:Thread-1 in while number:40 thread name:Thread-1 in while number:30 thread name:Thread-2 in while number:20 thread name:Thread-1 in while number:10 thread name:Thread-0 in while number:0 thread name:Thread-0 final number:0 thread name:Thread-1 in while number:-10 thread name:Thread-1 final number:-10 thread name:Thread-2 in while number:-20 thread name:Thread-2 final number:-20
雖然呼叫 TestThread 的方式為個別產生實體,但因為 mNumber 為 static field ,只佔一塊記憶體空間,屬於所有實體共享。
即使是不同實體也會存取到同一個mNumber,對 static field 的同步化必須特別注意才行。
有三種方式可以達到 static field 的同步化。
1. static synchronized method,缺點是 static method 內無法呼叫 non-static method。
public void run()
{
decreaseNumber();
}
private synchronized static void decreaseNumber()
{
while (mNumber >= 10) {
delayRandomMillSeconds();
mNumber -= 10;
System.out.println("thread name:"+getName()+" in while number:"+mNumber);
}
System.out.println("thread name:"+getName()+" final number:"+mNumber);
}
2. synchronized block with class object
public void run()
{
synchronized(TestThread.class){
while (mNumber >= 10) {
delayRandomMillSeconds();
mNumber -= 10;
System.out.println("thread name:"+getName()+" in while number:"+mNumber);
}
System.out.println("thread name:"+getName()+" final number:"+mNumber);
}
}
3. synchronized block with lock object
private static Object sLock = new Object();
public void run()
{
synchronized(sLock){
while (mNumber >= 10) {
delayRandomMillSeconds();
mNumber -= 10;
System.out.println("thread name:"+getName()+" in while number:"+mNumber);
}
System.out.println("thread name:"+getName()+" final number:"+mNumber);
}
}