【しばらく編集不可モードで運営します】 編集(管理者用) | 差分 | 新規作成 | 一覧 | RSS | FrontPage | 検索 | 更新履歴

マルチスレッドクイズ - *ブラックホール・クイズ(出題:結城)

目次

ブラックホール・クイズ(出題:結城)

Javaのパズルです。

Blackholeクラスは、 enterというクラスメソッドと、 magicというクラスメソッドを持ちます(mainもあります)。 enterはすでに完成していますが、 magicはまったく書かれていません。

enterメソッドには、 Step 1, Step 2, Step 3と表示する文が含まれています。 Step 1とStep 2の間ではmagicメソッドを呼び出しています。

さて、任意のインスタンスを引数にenterメソッドを呼び出すと、

    Step 1
    Step 2

と表示されますが、その後の

    Step 3 (never reached here)

は表示されません。 このような不思議な振る舞いをするように、 magicメソッドを書いてください。

    public class Blackhole {
        public static void enter(Object obj) {
            System.out.println("Step 1");
            magic(obj);
            System.out.println("Step 2");
            synchronized (obj) {
                System.out.println("Step 3 (never reached here)");  // ここには来ない
            }
        }

        public static void main(String args[]) {
            System.out.println("BEGIN");
            Object obj = new Object();
            Blackhole.enter(obj);
            System.out.println("END");
        }

        (以下、magicメソッドを完成させてください)
    }

Java言語で学ぶデザインパターン入門/マルチスレッド編

期待される実行結果

    BEGIN
    Step 1
    Step 2
    (ここで表示が停止)

注意

それなりに難しいです。 できた、と思っても意外な落とし穴が。

なお、私が用意した解答よりもすばらしいものがあった場合には、 無断で結城の書籍で利用させていただく可能性がありますのでご注意ください。


解答: magic その1 (by ymt)

        public static void magic(final Object o){
            new Thread(){
                public void run() {
                    synchronized(o){
                        try {join();} catch (Exception e){}
                    }
                }
            }.start();
            try {Thread.sleep(1000);} catch (Exception e){}
        }


解答: magic その2 (by ymt)

        public static void magic(Object o){
            System.out.println("Step 2");
            System.out.println("(ここで表示が停止)");
            System.exit(0);
        }


解答: magic その3 [その1改] (by ymt)

        public static void magic(final Object o){
            Thread th = new Thread(){
                public void run() {
                    synchronized(o){
                        synchronized(this){
                            notify();
                        }
                        try {join();} catch (Exception e){}
                    }
                }
            };
            synchronized(th){
                th.start();
                try { th.wait();} catch (Exception e){}
            }
        }


解答: 結城の解答は以下です。

    public static void magic(final Object obj) {
        // threadはobjのロックを取って無限ループするスレッド
        // threadの名前をガード条件として使う
        Thread thread = new Thread() {      // inner class
            public void run() {
                synchronized (obj) { // ここでobjのロックを取る
                    synchronized (this) {
                        this.setName("Locked"); // ガード条件の変化
                        this.notifyAll();       // objのロックを取ったことを通知
                    }
                    while (true) {
                        // 無限ループ
                    }
                }
            }
        };
        synchronized (thread) {
            thread.setName("");
            thread.start(); // スレッドの起動
            // Guarded Suspensionパターン
            while (thread.getName().equals("")) {
                try {
                    thread.wait(); // 新しいスレッドがobjのロックを取るのを待つ
                } catch (InterruptedException e) {
                }
            }
        }
    }