2

我正在尝试做的是让一个线程将从其父线程接收到的消息写入 OutputStream,侦听 InputStream 以获取回复,然后将回复通知父线程。我编写了两个测试类,它们以不同的方式做类似但更简单的事情。方法 1 仅在"before loop"调试语句未注释时有效,方法 2 仅打印"message from child"调试语句。我究竟做错了什么?

方法一

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();
                }               
            }   
        }       
    }
}

方法二

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

在方法 1 中,您有一个很好的死锁方法,因为父线程可以在子线程执行其 firstnotify()之前执行它的 first wait()。这将导致他们双方都在等待,而双方都无法通知。由于它是一种竞争条件,因此诸如打印语句之类的琐碎事情可能会影响实践中的行为。

方法 2 同样设计不佳,因为您有两个线程从同一个队列写入和读取。尝试使用两个队列,一个是父级写入,子级读取,另一个是子级写入,父级读取。

于 2012-04-15T14:16:46.747 回答