『増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』に載っているデザインパターンを Groovy/GPars で書こうシリーズ、今回は Producer-Consumer パターン。 Producer-Consumer パターンはやるべき仕事を見つけることとその仕事を実行することを互いに隔離し分離します(『Java並行処理プログラミング ―その「基盤」と「最新API」を究める―』) 非同期処理の基本であり真髄ってところでしょうか。
このデザインパターンも、Guarded Suspension パターンと同じく、java.util.concurrent パッケージに含まれる BlockingQueue インターフェースとそのサブタイプを使えば簡単に実装できます。
サンプル・コード
ここで作成するサンプルのソースは
- MakerActor クラス
- 実行スクリプト(テーブル、eater を含む)
です。 ケーキの Producer である MakerActor がケーキ(String オブジェクト)を作ってテーブル(BlockingQueue オブジェクト)に置き、ケーキの Consumer である eater がテーブルに置かれたケーキを食べます。 eater も Actor として作成しますが、実装が簡単なので実行スクリプトに直接書いてます。
MakerActor クラス
MakerActor は順々に番号が付けられたケーキを作ります。 番号は全ての MakerActor インスタンスで共通につけられるようにします:
import groovyx.gpars.actor.DefaultActor import java.util.concurrent.BlockingQueue class MakerActor extends DefaultActor{ private static int ID = 0 private final String name private final BlockingQueue<String> table private final Random random MakerActor(String name, BlockingQueue<String> table, long seed){ this.name = name this.table = table this.random = new Random(seed) } @Override protected void act() { loop{ Thread.sleep this.random.nextInt(1000) def cake = "[ Cake No. ${nextId()} by $name ]" this.table.put(cake) println "$name puts $cake" } } private static synchronized nextId(){ return ID++ } }
実行スクリプト
実行スクリプトでは Consumer 役の eater を Actors#actor() によって作成しています。 また、ケーキを置くテーブルは BlockingQueue (の実装クラスである ArrayBlockingQueue)として作成しています。 『増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』のサンプルと少々違って、標準出力への put/take のログ書き出しをテーブルの外で行っているので、ログ出力だけを見ると作られてるケーキの番号と順番が一致しない可能性もあります。 修正するには BlockingQueue のサブクラスなりラップクラスなりを作る必要があるので、ここでは妥協。
import java.util.concurrent.BlockingQueue import java.util.concurrent.ArrayBlockingQueue import groovyx.gpars.actor.Actor import groovyx.gpars.actor.Actors BlockingQueue<String> table = new ArrayBlockingQueue<>(3) def actors = [] actors << new MakerActor('MakerActor-1', table, 31415L).start() actors << new MakerActor('MakerActor-2', table, 92653L).start() actors << new MakerActor('MakerActor-3', table, 58979L).start() actors << eaterActor('EaterActor-1', table, 32384L) actors << eaterActor('EaterActor-2', table, 62643L) actors << eaterActor('EaterActor-3', table, 38327L) actors*.join() Actor eaterActor(String name, BlockingQueue<String> table, long seed){ return Actors.actor{ def random = new Random(seed) loop{ def cake = table.take() println "$name takes $cake" Thread.sleep(random.nextInt(1000)) } } }

増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2006/03/21
- メディア: 大型本
- 購入: 15人 クリック: 287回
- この商品を含むブログ (199件) を見る

- 作者: 関谷和愛,上原潤二,須江信洋,中野靖治
- 出版社/メーカー: 技術評論社
- 発売日: 2011/07/06
- メディア: 単行本(ソフトカバー)
- 購入: 6人 クリック: 392回
- この商品を含むブログ (152件) を見る