在多线程程序中未获得预期的结果

时间:2019-01-06 17:52:09

标签: java multithreading

我没有得到下面程序的预期结果,我期望生产者和使用者方法都应按一定顺序执行,但由于某种原因,只有生产者方法正在执行。

我在这里有两个问题:

  1. 我无法理解这种行为。
  2. 在main方法的最后一行将两个线程连接在一起正常,但我无法理解两者之间的区别。

    public class ProducerConsumer {
        List<Integer> data = new ArrayList<>();
    
         synchronized void  produce() throws InterruptedException {
            for (int i = 0; i < 10; i++) {
                System.out.println("Producing");
                data.add(i);
            }
            wait();
        }
    
        synchronized void consume() throws InterruptedException {
                System.out.println("Consuming");
                data.clear();
                notify();
        }
    
        public static void main(String[] args) throws InterruptedException {
            ProducerConsumer pc = new ProducerConsumer();
    
            Runnable r2 = ()-> {
                try {
                    pc.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            Thread thread1 = new Thread(r2);
            thread1.start();
            thread1.join();
    
    
    
    
            Runnable r1 = () -> {
                try {
                    pc.consume();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            Thread thread = new Thread(r1);
            thread.start();
            thread.join();
    
        }
    

    输出: 生产中 生产中 生产中 生产中 生产中 生产中 生产中 生产中 生产中 生产

2 个答案:

答案 0 :(得分:1)

produce()方法以wait()结尾。因此它将阻塞,直到有线程通知它为止。

执行此操作的唯一线程是使用者线程。但是,只有在生产者线程结束之后,才通过main方法启动消费者线程。它直到被通知才结束。这样您就陷入僵局。

如果仅在启动两个线程之后join(),则使用者线程可以启动而不必等待生产者线程完成。自那以来,这仍然不能使程序正确

  • 您无法保证生产者线程将首先执行
  • 在结尾处调用wait()是没有用的
  • 从循环中调用wait()检查条件不正确
  • 如果希望方法按顺序执行,则使用线程是没有用的。您可以从主线程执行所有操作。

答案 1 :(得分:0)

1)notify()调用根本不执行任何操作。除非其他线程已经已经等待要通知。

由您保证,只要您的一个线程调用wait()的任何时间,其他线程在{{1}之后的某个时间notify()都会同一个对象}已经开始。

Oracle的Guarded Blocks Tutorial很好地解释了wait()o.wait()的工作原理,并解释了如何建立保证。

2)几乎没有理由这样做:

o.notify()

您的程序将使用较少的CPU,并且将使用较少的内存,并且如果您只是调用Thread t = new Thread(r); t.start(); t.join(); ,则它将完成完全相同的操作。线程的整个点是为了允许发生不同的事情 concurrently ,并且如果一个线程r.run()之后紧接一个新线程,则不会并发创建它。除非您使用新的joins对象,否则将被浪费掉:

Thread

3)Thread t = new Thread(r); t.start(); doSomethingElseWhileThread_t_isRunning(); t.join(); wait()是线程之间进行通信的非常底层的方法。如果您使用在notify()wait()之上构建的higher-level synchronization objects而不是直接构建,则代码将更易于阅读和理解。  打电话给他们。

java.util.concurrent.ArrayBlockingQueue实例将特别适合于“生产者/消费者”应用程序。