IThaiのブログ

IT関連の話題やタイに関する様々なことを書いていきます。

Executorsでマルチスレッド処理を行う

バッチ処理とかで大量データ処理を行うを扱うときに、何時間以内で終わらせないといけない等の時間制約がある場合、マルチスレッド処理で処理時間を早めることはよくあります。

今回はJavaのjava.util.concurrent.Executorsを使ってマルチスレッド処理を実装してみました。

例:サンプル1000個の受注に対してすべて受注済み確定に変更する処理を行う。ただし、3つ目の受注は処理に3秒間かかるものと想定。

まずはメインスレッドを作ります。

package multi;

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

public class Main {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //サンプル受注1000個を作成
        List<Order> orders = createOrder();
        ExecutorService service = Executors.newCachedThreadPool();
        for (Order order : orders) {
            Task task = new Task();
            task.setOrder(order);
            Future<Order> future = service.submit(task);
        }
        service.shutdown();
    }

    private static List<Order> createOrder() {
        List<Order> orders = new ArrayList<Order>();
        for (int i = 0; i < 1000; i++) {
            Order order = new Order();
            order.setId(i);
            order.setName("注文" + i);
            orders.add(order);
        }
        return orders;
    }

}

次にタスクを作ります。タスク内容は受注1件を受け取って受注済み確定にする処理です。

package multi;

import java.util.concurrent.Callable;

public class Task implements Callable<Order> {
    
    private Order order;

    @Override
    public Order call() throws Exception {
        System.out.println("注文={" + order.getId() + ":" + order.getName() +"}を処理します");
        if(order.getId() == 3){
            Thread.sleep(3000);
        }
        order.setName(order.getName() + "(受注済み確定)");
        System.out.println("注文={" + order.getId() + ":" + order.getName() +"}です"); 
        return order;
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }
}

最後に注文内容です。

package multi;

public class Order {
    
    private int id;
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }

}

メインスレッドで作成したサンプル受注1000個をタスク(別スレッドとして作成)に渡して処理させます。(*3つ目の受注は処理時間が長いものと想定して、Thread.sleep()で3秒待たせます。)

実行結果

注文={0:注文0}を処理します
注文={0:注文0(受注済み確定)}です
注文={1:注文1}を処理します
注文={1:注文1(受注済み確定)}です
注文={2:注文2}を処理します
注文={2:注文2(受注済み確定)}です
注文={3:注文3}を処理します    <-------ここの処理に時間がかかる
注文={4:注文4}を処理します
注文={4:注文4(受注済み確定)}です
〜〜〜〜〜〜〜〜〜〜〜〜〜〜
〜〜〜〜〜〜〜〜〜〜〜〜〜〜
注文={998:注文998}を処理します
注文={998:注文998(受注済み確定)}です
注文={999:注文999}を処理します
注文={999:注文999(受注済み確定)}です
注文={3:注文3(受注済み確定)}です <-------最後に処理が完了している

確かに受注3つ目の処理が最後にきていますね。シングルスレッドなら、受注3つ目の処理が終わるのを待ってから、受注4つ目の処理が実行されますが、マルチスレッドでは処理を待つことなく後続の処理を実行していきます。マルチスレッドの強力さを実感できました。