單例模式的基本介紹
雖然單例模式中的 HungerSingleton 可以保證只產生一個實體,但其中的資料還是需要做好同步化的動作。
首先標準的 Hunger Singleton
public class HungerSingleton
{
private static final HungerSingleton sUniqueInstance = new HungerSingleton();
private List<Integer> mNumbers = new ArrayList<Integer>();
private HungerSingleton() {
// Prevents singleton instance being instantiated from outside
}
public static HungerSingleton getInstance()
{
return sUniqueInstance;
}
public void addNumber(int number)
{
mNumbers.add(number);
}
public List<Integer> getNumbers()
{
return mNumbers;
}
}
唯一不同的為第5行 mNumbers , 這個 List 將拿來做測試用,確保資料的同步化是否真的實現。
接著為Thread subclass
public class TestThread extends Thread
{
@Override
public void run()
{
for (int i = 0; i < 10; ++i) {
HungerSingleton.getInstance().addNumber(i);
}
}
}
相當簡單,在 run 中會取得 HungerSingleton 的實體並把數值加到 mNumbers 中。
測試 Main class
public class Main
{
public static void main(String[] args)
{
Thread thread = new TestThread();
thread.start();
Thread thread2 = new TestThread();
thread2.start();
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (Integer number : HungerSingleton.getInstance().getNumbers()) {
System.out.println("number:" + number);
}
}
}
目標為讓 HungerSingleton 的 mNumbers 內容為 2 組 0 到 10 按照順序排列的數值。
執行結果
number:0 number:0 number:1 number:1 number:2 number:3 number:2 number:4 number:3 number:5 number:5 number:4 number:7 number:6 number:8 number:9 number:6 number:7 number:8 number:9
可以看到因為多執行緒的關係造成 mNumbers 內容排序錯亂。
加上同步化機制
public class TestThread extends Thread
{
@Override
public void run()
{
synchronized (HungerSingleton.getInstance()) {
for (int i = 0; i < 100; ++i) {
HungerSingleton.getInstance().addNumber(i);
}
}
}
}
synchronized 可以讓一個執行緒取得指定物件的鎖,並擋住其他執行緒,直到該進入的執行緒完成函式內動作退出。
執行結果
number:0 number:1 number:2 number:3 number:4 number:5 number:6 number:7 number:8 number:9 number:0 number:1 number:2 number:3 number:4 number:5 number:6 number:7 number:8 number:9
從實驗結果可以看到雖然 HungerSingleton 可以保證只產生一個實體,但其內資料的操作還是需要加上同步化的動作。