LoginSignup
23
24

More than 5 years have passed since last update.

[コピペで動く] Javaで並列計算 [コードが欲しい]

Last updated at Posted at 2015-02-26

はじめに

Java初心者です.

概要

Javaで並列(並行)計算したいです.

Threadを直接操作する?方法は教わったことがあります. こんな感じ.

しかし, java.util.concurrentを使うことでもっと楽に処理できるみたいです. やってみました.

コード

ParallelTest.javaというコードを書いてみました.
8スレッド用意して, 8個のタスクを処理させます.

8個のタスクは, それぞれ処理に要する時間が異なるように設定しました.
タスク1は8秒, タスク2は7秒, タスク3は6秒, ..., タスク8は1秒かかります.

import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

class ParallelTest{
  public static void main(String[] args) {
    int threadNumber = 8;
    // 8スレッド用意
    ExecutorService executor = Executors.newFixedThreadPool(threadNumber);

    // 結果を入れる配列
    String[] results = new String[threadNumber];

    // タスクのリストを作る
    List<Callable<String>> tasks = new ArrayList<Callable<String>>();
    for(int i = 1; i <= threadNumber; i++){
      tasks.add(new ParallelTasks(i));
    }

    try{
      // 並列実行
      List<Future<String>> futures;
      try{
        futures = executor.invokeAll(tasks);
      } catch(InterruptedException e){
        System.out.println(e);
        return ;
      }
      System.out.println("-----------");

      // 結果をresultsに入れる
      for(int i = 0; i< threadNumber; i++){
        try{
          results[i] = (futures.get(i)).get();
        }catch(Exception e){
          System.out.println(e);
        }
      }
    } finally{
      // 終了
      if(executor != null) executor.shutdown();

      // 結果の配列の中身
      for(String result : results) System.out.println(result);
    }
  }
}

// 並列計算する内容
class ParallelTasks implements Callable<String>{
  int taskNumber;
  public ParallelTasks(int taskNumber){
    this.taskNumber = taskNumber;
  }

  @Override
  public String call() throws Exception{
    // sleep 
    // 開始が速いタスクほど時間がかかるように設定
    Thread.sleep((long)(1000 * (8 - taskNumber) ));

    // タスクの番号を出力
    System.out.println("task " + taskNumber + " end.");

    return "task " + taskNumber ;
  }
}

出力結果.

タスク終了の通知は, 早く終わったタスクの順番になるので, タスクの番号の逆順になっています.
しかし, 結果の配列を呼び出すと, 元々のタスクの順番になっています.

task 8 end.
task 7 end.
task 6 end.
task 5 end.
task 4 end.
task 3 end.
task 2 end.
task 1 end.
-----------
task 1
task 2
task 3
task 4
task 5
task 6
task 7
task 8

(実行時間: *** time: 8.096693 *** )

色々やっているように見えますが,
Executors.newFixedThreadPool(threadNumber)でスレッドを用意して,
タスクのリストをinvokeAllするだけです.

結果を呼び出すときに頑張っているのがFutureです.
(futures.get(i)).get()で, i番目のタスクの処理結果を呼びます.
このとき, 処理が終わっていない場合は, 処理が終わるまで待ってくれます.
タスク1は8秒かかるように設定していますから, get()を行った時にはまだ終わっていないはずですが, 終了するまで待ってから結果の格納を行っています.
なので, 結果の配列resultsには, タスクの番号順で格納されています.
Futureは, タスクの実行状態を加味した行動をしてくれるんですね. 助かります.

Callableがよく分からないのですが, とりあえず並列計算したい内容をcall()に書いて, 返り値の型と合わせれば動きました.

感想

Java難しい.

参考文献

http://itpro.nikkeibp.co.jp/article/COLUMN/20071001/283395/
http://tree-tips.appspot.com/java/executorservice/

次に読む

Threadの詳しい話

CompleteTableFutureの話(yohhoyさんありがとうございます)

Java8の話.

23
24
2

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
23
24