2

私がやろうとしているのは、親スレッドから受け取ったメッセージをスレッドに書き込んで OutputStream にし、応答を InputStream でリッスンしてから、親スレッドに応答を通知することです。私は、似たようなことを行う 2 つのテスト クラスを作成しましたが、異なる方法で単純化しました。方法 1 は"before loop"デバッグ ステートメントがコメント解除されている場合にのみ機能し、方法 2 は"message from child"デバッグ ステートメントのみを出力します。私は何を間違っていますか?

方法 1

public class Parent {
    private static int out = 0;
    private static int in = 0;

    public static void main(String[] args) {
        final Object locker = new Object();
        Thread t = new Thread(new Runnable() {          
            @Override
            public void run() {
                while (true) {
                    synchronized (locker) {
                        try {
                            locker.wait();
                            System.out.println("Message from parent " + out);
                            in = out + 10;
                            locker.notify();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        t.start();

        System.out.println("before loop");
        while (out < 10) {
            synchronized (locker) {
                locker.notify();
                try {
                    locker.wait();
                    out++;
                    System.out.println("Message from child " + in);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }               
            }   
        }       
    }
}

方法 2

public class Parent {

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        final BlockingQueue<Integer> q = new ArrayBlockingQueue<Integer>(1);

        Thread t = new Thread(new Runnable() {          
            @Override
            public void run() {
                while (true) {
                    try {
                        Integer i = q.take();               
                        System.out.println("Message from parent: " + i.intValue());
                        q.put(i.intValue() + 10);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }               
            }
        });

        for (int i = 0; i < 10; i++) {
            q.put(i);
            Integer j =  q.take();
            System.out.println("Message from child: " + j);
        }
    }

}
4

2 に答える 2

5

Java API はすでにその機能を提供しています。車輪を再発明する正当な理由がありますか?

public static void main(String[] args) throws Exception {
    // start a worker thread
    ExecutorService exec = Executors.newFixedThreadPool(1);

    // ask the worker thread to execute a task (
    Future<String> future = exec.submit(() -> {
        Thread.sleep(500); // simulate waiting for I/O
        return "hello from child";
    });

    // get the return value from the worker thread (waiting until it is available)
    String greeting = future.get();
    System.out.println(greeting);

    // terminate the worker thread (otherwise, the thread will wait for more work)
    exec.shutdown();
}
于 2012-04-15T14:38:20.350 に答える
1

notify()方法1では、子が最初のスレッドを実行する前に親スレッドが最初のスレッドを実行できるため、デッドロックの適切なレシピがありますwait()。これにより、両方が待機し、どちらも通知できなくなります。これは競合状態であるため、printステートメントのような些細なことが実際の動作に影響を与える可能性があります。

方法2も同様に、同じキューからの書き込みと読み取りの両方のスレッドがあるため、設計が不十分です。2つのキューで試してください。1つは親が書き込み、子が読み取り、もう1つは子が書き込み、親が読み取ります。

于 2012-04-15T14:16:46.747 に答える