【プログラミング中級者向け】さあ、マルチスレッドプログラミングをはじめよう その2

前回の続き

ではマルチスレッドを書く具体的な方法をお伝えします!

それは、、、

【Executor framework】です!!

Executor frameworkとは、、

スレッドプールをベースとしたシンプルな並列処理APIです。
処理を「Task」と言われる粒度に分解して考え、スレッドプールに割り当てて実行します。
TaskはRunnableインタフェースを継承したクラスまたはラムダ式で表現するため、実質的には「スレッドプールをサポートしたThreadの上位互換」として利用することが出来るでしょう。
また通常はFutureを取り扱えるExecutorServiceというExecutorを使います。

ややこしい!

簡単にまとめると、ExcutorServiceを使ってマルチスレッドの処理を書けるということです。

実際の処理がこちら。

public static void main(String[] args) throws Exception {
   ExecutorService es = Executors.newFixedThreadPool(2); //1
   try {
       es.execute(() -> System.out.println("executor:1, thread-id:" + Thread.currentThread().getId())); //2
       es.execute(() -> System.out.println("executor:2, thread-id:" + Thread.currentThread().getId()));
       es.execute(() -> System.out.println("executor:3, thread-id:" + Thread.currentThread().getId()));
       es.execute(() -> System.out.println("executor:4, thread-id:" + Thread.currentThread().getId()));
       es.execute(() -> System.out.println("executor:5, thread-id:" + Thread.currentThread().getId()));
   } finally {
       try {
				es.shutdown(); //3
				if (!es.awaitTermination(1, TimeUnit.MINUTES)) {  //4
					es.shutdownNow();  //5
				}
			} catch (InterruptedException e) {
				System.out.println("awaitTermination interrupted: " + e);
				es.shutdownNow();
			}
   }
}

実際の結果がこちら。

executor:1, thread-id:11
executor:2, thread-id:11
executor:3, thread-id:12
executor:4, thread-id:12
executor:5, thread-id:12

スレッドが11と12の2つで行われているため、マルチで実行されていますね!

では解説していきます!

1.マルチスレッドの処理を行えるサービスクラスExecutorServiceを宣言・初期化しています。このときExecutorsクラスのnewFixedThreadPool()メソッドを使い、指定数のスレッドを再利用するスレッドプールを設定しています。今回は11と12のidの2つのスレッドをプールしています。

2.ExecutorServiceクラスのexecuteメソッドで出力処理を実行しています。

ラムダ式で記述されており、匿名クラスが変換されています。

es.execute(new Runnable() {
	@Override
	public void run() {
		System.out.println("executor:1, thread-id:" + Thread.currentThread().getId());
	}
});

Eclipseならクイックフィックス(Cmd+1)でも確認できます!

3.ExcutorServiceクラスのshutdownメソッドを使って、シャットダウンを開始します。
shutdownメソッドは指示するだけ。
学校で先生が生徒に対して、「問題が解けたら教えてねー」と言います。
でも先生(shutdownメソッド)は何もしません。「先生できたー!!」って言ってくるまで「かたくな」に待ちますw
shutdownメソッドは指示するだけだからです。

4.そこでawaitTerminationメソッドです。
ある一定時間待ってもタスクが終わらない場合、
タスクを中断させることで、ずっとタスク完了を待つことをしないですみます。
使い方としては、shutdownメソッド実行後にawaitTerminationを実行します。
awaitTerminationの第一引数の時間だけ同期して待ちます。
指定した時間内に全てのタスクが完了した場合、trueを返します。
指定した時間経っても全てのタスクが完了しない場合、falseを返します。

falseを返されるというのは、授業の時間が終わっても、
問題が解けていない生徒がいる状態です。

5.なので「解けてない人宿題で明日提出しなさい!!」と言って授業を終わらせましょう!
shutdownNowメソッドがやってくれます。

shutdownNowメソッドは、実行中の全てのスレッドに対してinterruptedを発行してスレッドを中断します。

まとめると、

・ExecutorServiceサービスでマルチスレッド処理を書くことができる
・実行順序はshutdownメソッド、awaitTerminationメソッド、shutdownNowメソッド(例外発生時、タイムアウト時のみ)

ではまた次回の投稿をお楽しみに〜!


参考文献
https://qiita.com/koduki/items/086d42b5a3c74ed8b59e
http://mobiles-han.blogspot.com/2012/12/executorserviceshutdown.html
https://qiita.com/bremen/items/b87bff49565fc9abc91b

この記事が気に入ったらサポートをしてみませんか?