Description :

Single Threaded Execution 代表以一個線程執行的意思,也稱critical section(臨界區)
該 Pattern 用來限制只能讓一個線程進行,也是多線程的基礎。
 

Role

Shared Resource (SR)(共享資源):
SR是會被多線程共同存取的類別,該類別的方法可以分為2類:
1. Safe method : 多線程同時存取也不會出錯的方法。
2. UnSafe method : 多線程同時存取會出錯的方法,需要加上防護(synchronized)限制單線程去存取。e.g.,

        BankRunnable bankRunnable = new BankRunnable();
        Thread thread1 = new Thread(bankRunnable,"1");
        Thread thread2 = new Thread(bankRunnable,"2");
        thread1.start();
        thread2.start();

bankRunnable 就是 SR 的角色,因為它會被 thread1 thread2 共同存取。
 

public class BankRunnable implements Runnable{
    private Bank mBank;
    public BankRunnable(Bank bank) {
        mBank = bank;
    }
    public BankRunnable(){
        mBank = new Bank("in BankRunnable",1000);
    }
    @Override
    public void run() {
            makeDraw();
    }
  private synchronized void makeDraw() {
        System.out.println("Thread in makeDraw:"+Thread.currentThread().getName());
        while (mBank.getMoney() >= 100) {
            try {
                Thread.sleep(new Random().nextInt(500));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            mBank.withDraw(100);
            System.out.println("Thread:"+Thread.currentThread().getName()+" "+mBank.getName() + " " + mBank.getMoney());
            if (mBank.getMoney() < 0) {
                System.out.println("over draw");
            }
        }
    }
}

BankRunnable 的方法中,makeDraw 即為 unsafe method , 其他的方法即是 safe method
對於 unsafe method 必須加上 synchronized 來保證同步化。
 

When to use??

滿足以下 個條件
1. 多線程。
2. 出現 shared resource
3. shared resource 的狀態(屬性)會發生變化,若狀態(屬性)不會發生變化,不需要使用synchronized
 
 

Note :

1.使用 synchronized 需要注意死鎖(deadlock),死鎖為2個線程分別獲取鎖定,互相等待對方解鎖的情況。
發生死鎖,程序會無法進行下去。
但要達到死鎖也必須滿足下列其一:
        1.具有多個shared resource
        2.線程鎖定一個shared resource,還沒解鎖前就去鎖定另一個shared resource
        3.取得 shared resource 的參與者順序不固定。
只要破壞上述條件其一就可避免死鎖。
 
2.unsafe method 複寫問題,若有 subclass 繼承 BankRunnable 並複寫了 makeDraw() 方法,但沒有加上
synchronized來修飾,同步化的問題又會出現,可以使用 final 來修飾superclass避免繼承。
 
3. 原子操作:
synchronized 的方法同時只有一個線程可以操作,因此這個方法為原子的操作。
java的基本類型(除了longdouble以外)和物件的賦值和引用也都是原子的。
在宣告屬性時加上volatile 代表所有對該屬性的操作都是不可分割的。
 
4.因此 single threaded execution pattern 可以簡單的描述為以下步驟
1.找出多線程的 shared resource
2.找出shared resource unsafe method 方法。
3.unsafe method 方法加上 synchronized
4.考慮死鎖或其他效率問題。