普通、マルチスレッドの実装処理のサンプルは以下のようなコードになっていることが多い
public class Callee implements Callable {
public String call() throws Exeption {
return "hoge"; // output "hoge".
}
}
public class Caller {
private ExecutorService pool = Executors.newFixedThreadPool(5);
public void multi() {
for (int i = 0; i < 5; i++) {
Callee callee = new Callee();
pool.submit(callee);
}
}
}
サンプルとしてはこれで問題ないのだが、
「実業務で使っているとcall()というメソッド名ではいまいち何をする処理なのかわかりづらい。
また、Calleeクラスに複数のメソッドを追加して、条件で呼び分けたりしたくなることがあったりする。
コメントで補足したり、呼び出し別にクラスを作ったりしてもいいが、面倒だしそんな時間もないことが多い。
やはり、ソースコードはコードを見ただけで何をやっているか一目稜線なのがベスト。」
というのを勉強したので、以下の実装を推奨する。
public class Callee {
public String outputHoge() {
return "hoge"; // output "hoge".
}
public String outputPiyo() {
return "piyo";
}
}
public class Caller {
private ExecutorService pool = Executors.newFixedThreadPool(5);
public void multi() {
for (int i = 0; i < 5; i++) {
final Callee callee = new Callee();
pool.submit(new Callable<String>() {
public String call() {
return callee.outputHoge();
}
});
}
}
}
この実装は以下の点で最初の実装より優れている。
- 呼び出し先のメソッド名を具体的に命名可能
- 呼び出し元で呼び出し先メソッドを置換可能(callee.outputHoge()をcallee.outputPiyo()に変更するだけ)
- 呼び出し先がPOJOなので、マルチスレッドとシングルスレッドどちらでもロジックを流用可能
呼び出し元の実装は多少煩雑になるが、マルチスレッド処理として目立つ(呼び出し元ソースの中でCallableが見える)ので、かえって保守性が高いのではないか。
(2021/07/06)
コードにスペルミスがあったので訂正