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

Java 在多线程程序中未获得预期结果,java,multithreading,Java,Multithreading,我并没有得到下面程序的预期结果,我希望生产者和消费者方法都应该以某种顺序执行,但由于某种原因,只有生产者方法被执行 我有两个问题: 我无法理解这种行为 在main方法的最后一行将两个线程连接在一起工作正常,我无法理解两者之间的区别 public class ProducerConsumer { List<Integer> data = new ArrayList<>(); synchronized void produce() throws Inte

我并没有得到下面程序的预期结果,我希望生产者和消费者方法都应该以某种顺序执行,但由于某种原因,只有生产者方法被执行

我有两个问题:

  • 我无法理解这种行为
  • 在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();
    
        }
    
    公共类生产者消费者{
    列表数据=新的ArrayList();
    synchronized void product()引发InterruptedException{
    对于(int i=0;i<10;i++){
    系统输出打印(“生产”);
    数据.添加(i);
    }
    等待();
    }
    synchronized void consume()引发InterruptedException{
    系统输出打印项次(“消费”);
    data.clear();
    通知();
    }
    公共静态void main(字符串[]args)引发InterruptedException{
    ProducerConsumer pc=新的ProducerConsumer();
    可运行r2=()->{
    试一试{
    pc.product();
    }捕捉(中断异常e){
    e、 printStackTrace();
    }
    };
    螺纹1=新螺纹(r2);
    thread1.start();
    thread1.join();
    可运行r1=()->{
    试一试{
    pc.consume();
    }捕捉(中断异常e){
    e、 printStackTrace();
    }
    };
    螺纹=新螺纹(r1);
    thread.start();
    thread.join();
    }
    
    输出: 生产 生产 生产 生产 生产 生产 生产 生产 生产 生产

  • product()
    方法以
    wait()
    结束。因此它会阻塞,直到某个线程通知它

    唯一执行此操作的线程是使用者线程。但是使用者线程只有在生产者线程结束后才由main方法启动。并且在收到通知之前,它不能结束。因此,存在死锁

    如果仅在两个线程启动后才
    join()
    ,则使用者线程可以启动,而无需等待生产者线程完成。这仍然不能使程序正确,因为

    • 您不能保证生产者线程将首先执行
    • 在末尾调用wait()是无用的
    • 在循环外调用wait()检查条件是不正确的
    • 如果您希望方法按顺序执行,那么使用线程是无用的。您可以从主线程开始执行所有操作
      • 1)调用
        notify()
        根本不做任何事情。除非其他线程已经在等待通知

        由您来保证,每当您的一个线程调用
        wait()
        ,在
        wait()
        开始后的某个时间,其他线程将
        notify()
        同一对象

        Oracle很好地解释了
        o.wait()
        o.notify()
        的工作原理,并解释了如何建立这种保证

        2) 实际上没有理由这样做:

        Thread t = new Thread(r);
        t.start();
        t.join();
        
        您的程序将使用更少的CPU,它将使用更少的内存,如果您只调用
        r.run(),它将完成完全相同的任务
        相反。线程的整个要点是允许不同的事情发生,如果一个线程
        在创建一个新线程后立即连接它,那么就没有并发性。新的
        线程
        对象将被浪费,除非您对其执行类似操作:

        Thread t = new Thread(r);
        t.start();
        doSomethingElseWhileThread_t_isRunning();
        t.join();
        
        3)
        wait()
        notify()
        是线程之间非常低级的通信方式。如果您使用构建在
        wait()
        notify()
        之上的方法,而不是直接使用,那么代码将更易于阅读和理解 给他们打电话

        实例特别适合于“生产者/消费者”应用程序