Java 为什么生产者/消费者线程演示挂在错误的位置?

Java 为什么生产者/消费者线程演示挂在错误的位置?,java,multithreading,producer-consumer,Java,Multithreading,Producer Consumer,我试着写一个生产者/消费者线程演示,但结果是错的 消费类 public void consume(){ if(TaskQueue.getInstance().isEmpty()){ System.out.println("B1 "+Thread.currentThread().getName()); synchronized (pruductMonitor) { System.out.println("B2 "+Thread.c

我试着写一个生产者/消费者线程演示,但结果是错的

消费类

public void consume(){
    if(TaskQueue.getInstance().isEmpty()){
        System.out.println("B1  "+Thread.currentThread().getName());
        synchronized (pruductMonitor) {
            System.out.println("B2  "+Thread.currentThread().getName());
            if(TaskQueue.getInstance().isEmpty()){
                //如果任务空了
                //唤醒生产者
                System.out.println("notify A    "+Thread.currentThread().getName());
                pruductMonitor.notify();

            }
            System.out.println("B3  "+Thread.currentThread().getName());
            synchronized (customerMonitor) {
                System.out.println("B4  "+Thread.currentThread().getName());
                if(TaskQueue.getInstance().isEmpty()){
                    //挂起消费者
                    try {
                        System.out.println("B wait  "+Thread.currentThread().getName());
                        customerMonitor.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    }else{
        System.out.println("B running   "+Thread.currentThread().getName());
        TaskQueue.getInstance().getTask();
    }
}
生产者阶级

private void produce() {
    Bean b = new Bean();
    if (TaskQueue.getInstance().isFull()) {
        System.out.println("A1  "+Thread.currentThread().getName());
        synchronized (customerMonitor) {
            System.out.println("A2  "+Thread.currentThread().getName());
            if (TaskQueue.getInstance().isFull()) {
                // 如果队列满了,唤醒消费者
                System.out.println("notify B... "+Thread.currentThread().getName());
                customerMonitor.notify();

            }
            System.out.println("A3  "+Thread.currentThread().getName());
            synchronized (pruductMonitor) {
                System.out.println("A4  "+Thread.currentThread().getName());
                if (TaskQueue.getInstance().isFull()) {
                    try {
                        System.out.println("A wait  "+Thread.currentThread().getName());
                        pruductMonitor.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }

        }
    } else {
        System.out.println("A running   "+Thread.currentThread().getName());
        TaskQueue.getInstance().addTask(b);
    }
}
主类

public class Main {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    Object pruductMonitor = new Object();
    Object customerMonitor = new Object();

    TaskQueue.getInstance().setLimit(10);

      //生产者开动  
    new Thread(new Pruduct(pruductMonitor,customerMonitor)).start();  
    new Thread(new Pruduct(pruductMonitor,customerMonitor)).start();  
    new Thread(new Pruduct(pruductMonitor,customerMonitor)).start();  
    new Thread(new Pruduct(pruductMonitor,customerMonitor)).start();  
    //消费者开动  
    new Thread(new Customer(pruductMonitor,customerMonitor)).start();  
    new Thread(new Customer(pruductMonitor,customerMonitor)).start();  

    new Thread(new Runnable() {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(true){
                System.out.println("==============="+TaskQueue.getInstance().getNum()+"===============");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }).start();
}  
}

结果是

===================9===============

正在运行的线程-2

正在运行的线程-0

正在运行的线程-3

A1螺纹-1

A2螺纹-1

通知B。。。线程-1

A3螺纹-1

A4螺纹-1

B运行线程-4

等待线程1

正在运行的线程-2

B运行线程-4

===================9===============

B运行线程-5

正在运行的线程-0

正在运行的线程-3

B运行线程-5

B运行线程-4

A1螺纹-3

A1螺纹-2

A1螺纹-0

===================10===============

B运行线程-5

===================8===============

B运行线程-4

===================6===============

B运行线程-5

B运行线程-4

===================4===============

B运行线程-4

B运行线程-5

===================2===============

B运行线程-4

B运行线程-5

================0===============

B1螺纹-5

B1螺纹-4

B2螺纹-5

通知线程5

B3螺纹-5

================0===============

================0===============

================0===============

================0===============

================0===============


为什么在Producer.class中运行pruductMonitor.wait()之后,所有的Producer线程都挂起了synchronized(customerMonitor),而它应该挂起synchronized(pruductMonitor)?

您可能会遇到几个问题

始终在循环中等待,如:

while (!somecondition) 
    somelock.wait();
等待线程释放锁后;一旦线程唤醒并重新获取锁,它需要再次检查状态。在一个线程得到通知并被唤醒的时间和该线程获得锁的时间之间可能会发生很多事情,导致该线程被通知的状态可能会在该时间间隔内再次发生变化

其次,在一个位置以一个顺序获取多个锁,在另一个位置以相反的顺序获取多个锁是导致死锁的好方法。如果您希望在这里确保notify始终影响相关线程(消费者不会收到生产者相关条件的通知,反之亦然),那么最好使用带有两个单独条件的ReentrantLock,而不是像这样处理两个内在锁。有关条件类,请参见API

这太复杂了,很大程度上是因为锁定与正在访问的数据结构分离。锁定的目的是防止线程对数据结构进行不安全的操作。将锁定放在任务队列中,而不是放在生产者和消费者中,这将变得更易于管理

synchronized(a){synchronized(b){}}
synchronized(a){synchronized(b){wait;}}}
我想所有的生产者线程都挂在a上,因为wait线程有一个?而消费者线程可以通知B,也可以挂A!哦,我知道,非常感谢