LoginSignup
151
174

More than 5 years have passed since last update.

ExecutorServiceを使って、Javaでマルチスレッド処理

Last updated at Posted at 2013-12-28

基本パターン(単一スレッド)

別スレッドにするタスクの作成

別にスレッドにしたい処理を、Runnable インタフェースを実装したクラスのrumメソッドに実装する。

public class TestRunnable implements Runnable {

    public void run() {
        // スレッドIDを出力する
        System.out.println(Thread.currentThread().getId());
    }
}

スレッドの生成とタスクの実行

ExecutorService クラスを利用して、スレッドの生成・タスクの実行を行う。
ここでは、「newSingleThreadExecutor」でスレッドを一つのみ生成し、5回タスクを実行している。

ExecutorService exec = Executors.newSingleThreadExecutor();

for (int i = 0; i < 5; i++) {
     exec.submit(new TestRunnable());
}

実行結果

1スレッドのみなので、すべて同じスレッドIDが出力される。

44
44
44
44
44

固定数の複数スレッド生成

newFixedThreadPoolを使用すると、固定数のスレッドを生成できる。

// 引数に生成するスレッド数を渡す
ExecutorService exec = Executors.newFixedThreadPool(3);

for (int i = 0; i < 5; i++) {
     exec.submit(new TestRunnable());
}

3つの固定スレッドを生成したので、3つのスレッドを使いまわしている。

24
24
24
26
25

必要に応じて複数スレッド生成

newCachedThreadPoolを使用すると、必要に応じてスレッドを生成する。
60秒間使用されなかったスレッドは破棄され、60秒未満であれば再利用される。

 ExecutorService exec = Executors.newCachedThreadPool();

 for (int i = 0; i < 5; i++) {
     exec.submit(new TestRunnable());
 }

 Thread.sleep(1 * 5000);
 System.out.println("--------5秒後---------");

 for (int i = 0; i < 5; i++) {
     exec.submit(new TestRunnable());
 }

 Thread.sleep(1 * 70000);
 System.out.println("--------70秒後---------");

 for (int i = 0; i < 5; i++) {
     exec.submit(new TestRunnable());
 }

3回に分けて処理を実行。
最初の実行から、5秒後に実行した処理は同じスレッドを再利用している。
70秒後の実行では既にスレッドが破棄されて、新しいスレッドが生成されている。

26
24
25
27
28
--------5秒後---------
24
27
28
25
26
--------70秒後---------
31
33
30
32
29

実行結果を取得する

実行結果を返すタスクの作成

実行結果を返す処理は、Callableインタフェースを実装したクラスのcallメソッドに実装する。

public class TestCallable implements Callable<Long> {
    public Long call() throws Exception {
        //スレッドIDを返す
        return Thread.currentThread().getId();
    }
}

タスクの実行と実行結果の取得

タスクの実行は、結果を返さない場合と同じく ExecutorService を使用するが、
戻り値としてFutureインタフェースを受け取る。

List<Future<Long>> list = new ArrayList<Future<Long>>();
for (int i = 0; i < 10; i++) {
    Future<Long> future = exec.submit(new TestCallable());
    list.add(future);
}

//Future#getメソッドで結果を取得できる。実行中の場合は終了まで待つ。

for (Future<Long> future : list) {
   try {
       Long id = future.get();
   } catch (InterruptedException e) {
       e.printStackTrace();
   } catch (ExecutionException e) {
       e.printStackTrace();
   }
}

引数を指定することで、指定した時間だけ実行結果を待つことができる。
指定した時間を超えると、TimeoutExceptionがスローされる。

//1秒間だけ待つ。
Long id = future.get(1, TimeUnit.SECONDS);
151
174
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
151
174