倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

Groovy で Balking パターン

増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』に載っているデザインパターンを Groovy/GPars で書こうシリーズ、今回は Balking パターン。 前回見た Guarded Suspension パターンでは、(キューが空になったり空きができたりなどのような)条件が満たされるまで処理のリクエスト側が待たされるのに対して、Balking パターンでは条件が満たされていなければすぐに処理を返します。 ってことで、条件の判定に使うフィールドやメソッドをキチンとスレッド対応にしましょう。

サンプル・コード


サンプルで作成するソースは

  • Data クラス
  • 実行スクリプト

です。 Balking パターンで重要なのは Data クラスのスレッド対応です。 『増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』には、他に ChangerThread, SaverThread が作られてますが、このパターンではそんなに重要ではないので、ここでは簡単に Actor として作っています(実行スクリプト参照)。

Data クラス

Data クラスは文字列の内容を持つデータを表し、ファイルへのセーブ機能も持っています。 セーブは save() メソッドにより行われますが、内容が変化されていなければ保存処理は行われません。

class Data {
    
    private String content
    private final File file
    private boolean changed
    
    Data(String filename, String content){
        this.file = new File(filename)
        this.content = content
        this.changed = true
    }
    
    synchronized void change(String newContent){
        this.content = newContent
        this.changed = true
    }
    
    /** name は保存を実行した Actor 名 */
    synchronized void save(String name){
        if(this.changed){
            println "$name calls save, content = $content"
            this.file.text = this.content
            this.changed = false
        }
    }
}

Date オブジェクトが複数のスレッドからアクセスされる場合、内容が変更されたかどうかのフラグ changed の値を変更する処理は同期化された状態で行う必要があります。 よって change(), save() メソッドは synchronized になっています。

実行スクリプト

では実行スクリプト。 changer はデータの変更と手動でのセーブを行い、saver は自動でのセーブを行います:

import groovyx.gpars.actor.Actors

final def data = new Data('data.txt', '(empty)')    // 必ずしも final にする必要はないけど

// 内容変更と手動セーブをエミュレート
def changer = Actors.actor{

    def i = 0
    def random = new Random()

    loop{
        data.change("No. $i")
        i++
        Thread.sleep random.nextInt(1000)
        data.save('ChangerActor')
    }
}

// 自動セーブをエミュレート
def saver = Actors.actor{
    loop{
        data.save('SaverActor')
        Thread.sleep 1000
    }
}

[changer, saver]*.join()    // Actor オブジェクトは join() しましょう

同じことを延々と実行するのは Actor の loop を使って実装しています。

増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編

増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編


プログラミングGROOVY

プログラミングGROOVY