2010년 5월 31일 월요일

デッドロックの確認

http://www.fumikichan.net/prog/Java/se030201.jsp

 

デッドロックの確認


1.デッドロックとは

 マルチスレッドを行うプログラムでは、複数のスレッドがお互いにロックの解放を待ち合い続けることによりシステムWait状態になる場合があります。 この現象をデッドロック(deadlock)といい、正常なプログラミングを行っていても、特定のオブジェクトのアクセスする順序により発生してしまいます。 デッドロックが発生しないようにするには、この特定のアクセス順序のルールを検討する必要があります。

 下の図でデッドロックが発生するまでの流れを説明します。

  • オブジェクトAとBを持つクラスから、お互いのオブジェクトを参照するスレッド1とスレッド2を生成します。
  • スレッド1はオブジェクトAのロックを取得し、オブジェクトBのロック解除を待っています。
  • スレッド2はオブジェクトBのロックを取得し、オブジェクトAのロック解除を待っています。
  • どちらのスレッドも互いにロックしたオブジェクトの解除を待つことになり永遠にWait状態になります。
デッドロックの流れ
 

2.プログラムの仕様

 では上記のデッドロックを実際にコーディングすることにより確認してみることにします。 プログラムは1クラスでも可能ですが、なるべく「デッドロックの流れ」の図に合うように3つのソースで5クラスに分けて作成します。

 簡単なプログラムの概要を下記に示します。

  • オブジェクトAとBはクラスAクラスBとし、それぞれ画面表示の2つのメソッドを持ちます。

  • オブジェクトAとBの実体はメインクラス(DeadlockTest)上にあり、他のクラスに参照設定を渡します。

  • メインクラス(DeadlockTest)からThreadAクラスのスレッドとThreadBクラスのスレッドを生成し、 両方のスレッドが終了したら終了メッセージを表示します。(デッドロックが発生した場合は表示されません。)

  • ThreadAクラスはオブジェクトAのロックを取得して、クラスAのメソッドを実行し、その後オブジェクトBのロックを取得して、クラスBのメソッドを実行します。

  • ThreadBクラスはオブジェクトBのロックを取得して、クラスBのメソッドを実行し、その後オブジェクトAのロックを取得して、クラスAのメソッドを実行します。

  • どちらのスレッドクラスもメソッド呼び出し処理をスレッド処理(run)の中で複数回(100回)行います。

なんとなく気になったので、Singleton を破壊するための TIPS

http://d.hatena.ne.jp/SiroKuro/20080403/1207236878

 

なんとなく気になったので、Singleton を破壊するための TIPS を余談として提示してみます。

結局クラスが一意であることを利用してクラスを1対1に結びついた単一のオブジェクトを作ってるだけなんだから

証明を書くには余白が足りない - 西尾泰和のはてなダイアリー

結局、クラスが一意じゃなければ、Singleton は破壊できちゃうんですよね。

今回破壊する Singleton はこういうクラスです。いたってシンプル

public class Singleton {
    private static final Singleton instance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() { return instance; }
}

これを、こういうコードからロードしてみちゃったりします。だいぶ乱暴なことをしますね。

import java.io.*;
class test {
    public static void main(String[] args) throws Exception {
        System.out.println(newInstance() == newInstance());
    }
    private static Object newInstance() throws Exception {
        File file = new File("Singleton.class");
        final byte[] data = new byte[(int)file.length()];
        new FileInputStream(file).read(data, 0, data.length);
        return new ClassLoader() {
            public Class<?> destroySingleton() {
                return defineClass("Singleton", data, 0, data.length);
            }
        }.destroySingleton().getMethod("getInstance").invoke(null);
    }
}

結果は "false"

defineClass のたびに、新しい Singleton クラスが返ってきます。

素人にはお勧めできない。

微妙にクラスが一意という条件は満たしていますが、1つのクラスファイルから複数個の Class をロードできる、という例でした。

追記

上記コード

-    private static Object newInstance() throws Exception {
+    private static Singleton newInstance() throws Exception {

-        return new ClassLoader() {
+        return (Singleton) new ClassLoader() {

のように変更すると、もちろんコンパイルは通るんですが、実行すると

Exception in thread "main" java.lang.ClassCastException: Singleton cannot be cast to Singleton
        at test.newInstance(test.java:10)
        at test.main(test.java:4)

という、世にも奇妙な例外を吐き出してきます。

やっぱり素人にはお勧めできない。

Singleton オブジェクトをシリアル化したいときには

シリアル化したい場合は

http://d.hatena.ne.jp/SiroKuro/20080403/1207237637#c1207267140

ということで、Singleton オブジェクトシリアル化したいときには、こういう風にします。

import java.io.*;
public class Singleton implements Serializable {
    private static final Singleton instance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() { return instance; }
    public Object readResolve() throws ObjectStreamException { return instance; }
}

Serializable くっつけて、readResolve という名前のメソッドを用意します。これで ObjectInputStream#readObject で返ってくるオブジェクトが、常に Singleton#instance になるという仕掛けです。

ということで Singleton 付けても readResolve を適切に実装すれば問題無い、という tips です。

memo(thread deadlock 調査)

http://blog.naver.com/leedc111/40034194835

 

 

http://www.nminoru.jp/~nminoru/java/jrockit70.html

http://otndnld.oracle.co.jp/document/products/jrockit/releases/R27/relnotes/r27_notes.html#wp1009832

スピンロックの使用
http://docs.sun.com/app/docs/doc/819-0390/ggecq?l=ja&a=view

http://download.oracle.com/docs/cd/E13188_01/jrockit/docs142/userguide/index.html
http://www.infoq.com/jp/articles/java-threading-optimizations-p1
エスケープ解析 - ロック除去
バイアスド・ロック
ロックの疎粒度化

http://download.oracle.com/docs/cd/E13188_01/jrockit/docs142/userguide/apstkdmp.html
Monitoring Information in Stack Dumps
Detecting Deadlocks

 

http://www.itarchitect.jp/news/-/107369.html

http://blogs.oracle.com/jrockit/2010/03/class_loading_deadlocks.html
Class Loading Deadlocks

 

http://blogs.oracle.com/jrockit/2010/01/why_wont_jrockit_find_my_class.html
Why won't JRockit find my classes

http://otndnld.oracle.co.jp/document/products/jrockit/docs142/userguide/apstkdmp.html