javaで並列処理させようとすれば、Thread作って、startして~~となりがちなことが
多いですが、
JavaSE5の時代からすでにExecutorServiceという便利な代物が存在します。
これはThread管理をライブラリ側で肩代りしてくれるので、
実装者がThreadの生成・破棄については考慮することなく使用することができます。
とりわけ、普通にループしてたメソッドの性能が出ないなどの理由で、
マルチスレッドでガッとやってしまえ!!という時に絶大な効果を発揮します。
以下にサンプルを掲載します。
マルチスレッドで実行されるメソッド
以下のようなクラスのrunメソッドを実行するとします。
ここでは3秒待機するだけのメソッドとなります。
この部分が本来時間短縮したいメソッド処理部分のイメージです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package jp.co.tarchan.executorservice; /** * スレッドで実行したいメソッドを含むクラス. * * @author Tar-Chan */ public class ExecutorServiceSample { /** * 実行対象メソッド. */ public void testMethod() { try { Thread.sleep(3000L); } catch (Exception e) { e.printStackTrace(); } } } |
マルチスレッドで実行するメソッド
以下のように使用することで、マルチスレッドで実行させることが
できます。
コメントにあるように普通に10回実行すると、30秒かかるものが、
5スレッドで実行するので、全体で6秒ほどになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
package jp.co.tarchan.executorservice; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.stream.IntStream; import com.google.common.collect.Lists; /** * ExecutorService実行部. * * @author Tar-Chan */ public class ExecutorServiceMain { /** * メイン処理. * * @param args 実行引数(今回はないよ) */ public static void main(String[] args) { ExecutorServiceSample sample = new ExecutorServiceSample(); // 通常10回実行すると、当然30秒かかる Long start = System.currentTimeMillis(); IntStream.range(0, 10).forEach(i -> { sample.testMethod(); }); Long end = System.currentTimeMillis(); System.out.println("sequencial process elapsed => " + (end - start) + "ms"); // これをスレッド5個で並列実行すると・・・ // 1スレッドあたり6秒で完結するので、 // 全体として6秒あたりで完結することになる start = System.currentTimeMillis(); // 待ち合わせリスト(Futureリスト) List<Future<?>> futureList = Lists.newArrayList(); // ExecutorService スレッドは5個で実行 ExecutorService service = Executors.newFixedThreadPool(5); // 同じように10回分の処理をスレッドに投入する // submitはcallble or runnableな何かなので、 // ラムダで無名関数として定義した中で、 // 対象メソッドを呼ぶ IntStream.range(0, 10).forEach(i -> { futureList.add(service.submit(() -> { sample.testMethod(); })); }); // Futureは完了までgetメソッドをブロックしてくれる // つまりここで待ち合わせをするということ for (Future<?> future : futureList) { try { future.get(); } catch (Exception e) { e.printStackTrace(); } } end = System.currentTimeMillis(); System.out.println("parallel process elapsed => " + (end - start) + "ms"); } } |
TPO限られるかもですが・・・
業務ロジックで性能が出ないものは、このようにマルチスレッドに
処理させることでうまくいくこともあるかもしれません。
ですが、トランザクションが絡んできたり、あるデータの状態遷移が
絡んでくる場合は、なかなかマルチスレッドによる適用が
難しい場面もあると思います。
マルチスレッドに動作させることが適当であるかどうかは、
TPOによるかもしれませんが、
うまくハマれば絶大な効果が得られると思います。

20代前半までは東京で音楽をやりながら両手の指以上の業種でアルバイト生活をしていましたが、某大手プロバイダのテレアポのバイトでPCの知識の無さに愕然とし、コンピュータをもっと知りたい!と思ったことをきっかけに25歳の時にITの世界に未経験で飛び込みました。
紆余曲折を経て、現在は個人事業主としてお仕事させていただいており、10年ほどになります。
web制作から企業システム構築、ツール開発など、フロントエンドもバックエンドもサーバーもDBAも依頼があれば何でもやってきた雑食系エンジニアです。
今風にいうとフルスタックエンジニアということになるのかしら??
→ 詳細プロフィールというか、生い立ちはこちら
→スキルシートをご覧になる場合はこちら
→お仕事のご依頼やお見積りなどお問い合わせはこちらから!