這是對在 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); } }