うさがにっき

読書感想文とプログラムのこと書いてきます

スレッドあれこれ

概要

スレッドについて以下の二点についてまとめる

  • スレッドプール
  • スレッドの処理結果をメインスレッドで受け取る

詳細

スレッドプール

アプリで使用するスレッドをあらかじめ用意しておいて、必要に応じて使う
スレッドプールを使うにはjava.util.concurrentパッケージを使う

            ExecutorService service = Executors.newFixedThreadPool(5);

            service.execute(new ThreadPoolBasic("thread1"));
            service.execute(new ThreadPoolBasic("thread2"));

            service.shutdown();

スレッドプールを使うにはjava.util.concurrentのExecutorsを利用する
Executorsクラスには以下のようなスレッドプールを作成するメソッドがある

newFixedThreadPool(int nThreads) 固定数のスレッドを確保
newSingleThreadExecutor() 単一のスレッドを確保、再利用
newCachedThreadPool() 必要都度に新規スレッドを作成、利用可能であれば以前のスレッドを再利用
newSingleThreadScheduledExecutor() 指定時間単位で実行されるスレッドを管理
newScheduledThreadPool(int corePoolSize) 指定時間単位で実行されるスレッドを管理

上記メソッドの返り値はExecutorServiceまたはその派生インタフェースであるScheduledExecutorService
ExecutorServiceオブジェクトからはexecuteメソッドを呼び出すことで、スレッドプールにスレッドを割り当て実行できる
shutdownメソッドはスレッドプールを破棄する、shutdownメソッドが呼び出された場合実行中のスレッドは完遂するが、新規のタスクはもう受け付けない

定期的な処理を実行するにはnewSingleThreadScheduledExecutor or newScheduledThreadPoolを使う

            ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
            service.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    
                }
            }, 0 , 1000, TimeUnit.MILLISECONDS);

定期的な実行スケジュールを定義するには以下のいずれかのメソッドを使う

delay経過後にperiodごとに処理を実行する
scheduleAtFixedRate, scheduleWithFixedDelayの違いはjavadoc参照、ざっくり言うと処理の繰り返すタイミングが違う

スレッドの結果を受け取る

戻り値を要する状況では、ExecutorService + Callableインタフェースを利用する

public class ThreadCall implements Callable<String>{
    @Override
    public String call() throws Exception {
        return "String";
    }

    public void main() {
        ExecutorService service = Executors.newFixedThreadPool(5);
        // Future<V>で結果を受け取る
        Future<String> f1 = service.submit(new ThreadCall());
        Future<String> f2 = service.submit(new ThreadCall());
        Future<String> f3 = service.submit(new ThreadCall());

        try {
            System.out.println(f1.get());
            System.out.println(f2.get());
            System.out.println(f3.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Futureは非同期処理の結果を返すオブジェクト、ジェネリクスはCallableの型パラメータと一致している必要がある
getメソッドは、非同期処理が終了していない場合、処理をブロックする

参考

AndroidエンジニアのためのモダンJava

AndroidエンジニアのためのモダンJava

広告を非表示にする