今天要介紹 Single Threaded Execution 模式,其實從它的字面翻譯就可以知道它是一個單執行緒執行模式,在什麼情境之下會使用到此模式?主要是有多個執行緒要存取同一個共享變數時會使用到此模式,就像是在 Day 7 時有介紹到為何要使用 Synchronized 來保護共享變數。因為我們無法去預期有可能不同的執行緒同時存取相同的變數,造成程式出錯。
以下使用執行緒不安全的方式,寫一個 Sample Code:
public class Data {
private String value1 = "";
private String value2 = "";
public void setValue(String value1, String value2) {
this.value1 = value1;
this.value2 = value2;
System.out.println(this.value1 + " " + this.value2 + " " + isValueEquals());
}
private boolean isValueEquals() {
return this.value1.equals(this.value2);
}
}
以上的 Data 類別主要是一個可以給多個執行緒使用的 class,它的功能就是在不同的執行緒會設定不同的值,目的是用來測試執行緒安不安全
public class ThreadExample implements Runnable {
private Data data;
private String value1;
private String value2;
public ThreadExample(Data data, String value1, String value2) {
this.data = data;
this.value1 = value1;
this.value2 = value2;
}
@Override
public void run() {
try {
while (true) {
Thread.sleep(500L);
this.data.setValue(this.value1, this.value2);
}
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
執行緒程式裡面主要會把主程式設定的值傳入,設定給 Data 的共享變數裡面,以下是主程式 Sample Code:
public class Test1 {
public static void main(String args[]) {
Data data = new Data();
for (int i = 1 ; i <= 1000 ; i++) {
Thread thread = new Thread(new ThreadExample(data, "value" + i, "value" + i));
thread.start();
}
}
}
在主程式裡面會使用迴圈開 100 個執行緒來執行,ThreadExample 的執行緒建構子會傳入相同的值,用來確認共享變數會不會被其它的執行緒干擾,執行的結果如下:
value308 value308 true
value353 value353 true
value283 value283 true
value349 value349 true
value305 value305 false
value337 value337 true
value335 value335 true
value363 value363 true
value309 value309 true
value375 value375 true
從執行的結果來看 Data 類別是執行緒不安全的程式,因為雖然印出 value305 的值都是相同的,但卻印出 false 所以在執行的過程中有被其它的執行緒干擾,才會印出 false。要修改此問題需要修改 Data 這個類別,程式如下:
public class Data {
private String value1 = "";
private String value2 = "";
public synchronized void setValue(String value1, String value2) {
this.value1 = value1;
this.value2 = value2;
System.out.println(this.value1 + " " + this.value2 + " " + isValueEquals());
}
private boolean isValueEquals() {
return this.value1.equals(this.value2);
}
}
在 setValue 的方法前面加上 Synchronized 的關鍵字就可以解決這個問題,但這會影響到多執行緒執行的效能因為要另外的去等待其它執行執行完才會進入執行。如果在意執行效能的話需要把 Data 類別修改成前幾天介紹的 Immutable 模式,也是另外一個解決共享變數互斥的方法。