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