倭マン's BLOG

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

Groovy で Double-checked Locking パターン

増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』に載っているデザインパターンを Groovy/GPars で書こうシリーズ、今回は Double-checked Locking パターン。 このパターンは、複数のスレッドからアクセスされる可能性のあるフィールドの遅延初期化 (lazy initialization) を行いたいときに用います。 static フィールドの遅延初期化は Initialization On Demand Holder パターン(次回やる予定)を用いるのが最善とされてますが、インスタンスフィールドの場合には使えないので、少々込み入っているこの Double-checked Locking パターンが必要です。 マルチスレッド・プログラミングの書籍には大抵書いてますが、このパターンは Java 1.4 以前で用いると予期せぬ初期化がされる可能性があります。

参考 URL

サンプル・コード その1


Double-checked Locking パターンの典型的なコード。 『Effective Java 第2版 (The Java Series)』を参考にしています:

class MyClass {
    
    private volatile MyField field
    
    MyField getField(){
        MyField result = this.field
        if(result == null){
            synchronized(this){
                result = this.field
                if(result == null)this.field = result = new MyField()
            }
        }
        return result
    }
}

class MyField{}
  • フィールドの volatile 宣言を忘れずに!
  • ローカル変数 result は使わなくても動作しますが、使った方がパフォーマンスが向上するそうです(既に初期化が完了している場合のメソッド呼び出しに於いて)。
  • volatile 宣言されているフィールドの読み込みは、最近の JVM ではほとんどコストなく実行できるそうなので、上記のコードは getter メソッド自体を synchronized にするよりもパフォーマンスがよいそうです(試してませんが)。

サンプル・コード その2


次は Groovy の @Lazy アノテーションを用いたサンプル。

class MyClass {
    @Lazy volatile MyField field = new MyField()
}

こちらでも volatile 宣言を忘れずに。 @Lazy アノテーションを付加することによってローカル AST 変換が行われ、「サンプル・コード その1」のようなコードに書き換えられます(詳しくは @Lazy アノテーションのドキュメントを参照のこと)。 フィールドの初期化に処理が必要な場合は「クロージャ+ () 」を用います:

class MyClass {
    @Lazy volatile MyField field = { /* インスタンスを生成する処理 */ }()
}

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

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


プログラミングGROOVY

プログラミングGROOVY