前言
實現Runnable接口是啓動多線程最常見的方式, 而這個過程中我們實則使用了策略模式
策略模式UML圖
策略模式有以上角色: 抽象策略(Strategy)), 具體策略, 環境上下文(Context), 其中Context角色依賴Strategy
一個策略模式案例
@FunctionalInterface
// Strategy角色, 也是函數式接口
public interface Strategy {
double calculate(double salary, double bonus);
}
// Context 上下文環境, 依賴Strategy
public class TaxCalculator {
// 工資
private final double salary;
// 獎金
private final double bonus;
// 計稅策略
private Strategy strategy;
public TaxCalculator(double salary, double bonus, Strategy strategy) {
this.salary = salary;
this.bonus = bonus;
this.strategy = strategy;
}
public double getSalary() {
return salary;
}
public double getBonus() {
return bonus;
}
protected double calculate(){
return strategy.calculate(salary,bonus);
}
}
// 測試類, 用Lambda表達式表示具體策略實例
public class Test {
public static void main(String[] args) {
TaxCalculator calculator1 = new TaxCalculator(10000d, 2000d,
(salary, bonus) -> salary * 0.1 + bonus * 0.15);
TaxCalculator calculator2 = new TaxCalculator(15000d, 4000d,
(salary, bonus) -> salary * 0.15 + bonus * 0.20);
System.out.println(calculator1.calculate());
System.out.println(calculator2.calculate());
}
}
一個實現Runnable接口啓動多線程的實例
// Runnable就是抽象策略接口, 本類就是具體策略類, run() 方法封裝了具體實現
public class TicketWindowRunnable implements Runnable {
private int index = 1;
private final static int MAX = 1000;
public void run() {
while (index <= MAX){
System.out.println(Thread.currentThread() + "的號碼是" + (index++));
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 模擬銀行櫃檯叫號, Thread類可對照策略模式中的 Context角色
public class Bank2 {
public static void main(String[] args) {
final TicketWindowRunnable ticketWindow = new TicketWindowRunnable();
// 依賴具體Strategy 角色
Thread t1 = new Thread(ticketWindow,"1號窗口");
Thread t2 = new Thread(ticketWindow,"2號窗口");
Thread t3 = new Thread(ticketWindow,"3號窗口");
t1.start();
t2.start();
t3.start();
}
}
// 參考Thread類的start()方法源碼, 着重關注 start0() 方法
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0(); // 這是個native方法, 會調用具體策略中的 run() 方法, 並開啓線程
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
總結
與策略模式做類比可以更好地理解通過實現Runnable接口啓動多線程的寫法
把Thread類看做Context上下文角色, Runnable接口看做抽象策略角色, 而具體策略角色由開發者自己定義(也就是重寫run方法)
開啓多線程的方法: new Thread(Runnable runnable, String name). start()
, 對照Context角色依賴Strategy角色的方式就很好理解了