Java多线程程序(生产者和消费者)挂起。。?

Java多线程程序(生产者和消费者)挂起。。?,java,multithreading,deadlock,producer-consumer,Java,Multithreading,Deadlock,Producer Consumer,我有一个简单的Java生产者和消费者示例的变体。我认为它应该可以工作,但它挂了。我最初认为它可能是某种形式的死锁,但是当我查看线程转储时,它似乎陷入了无限循环的中间。无论如何,我不明白为什么程序的行为如此奇怪,我想知道一个可能导致挂起的场景 public class ProducerConsumer { public static void main(String[] args) { Buffer buffer = new Buffer(7);

我有一个简单的Java生产者和消费者示例的变体。我认为它应该可以工作,但它挂了。我最初认为它可能是某种形式的死锁,但是当我查看线程转储时,它似乎陷入了无限循环的中间。无论如何,我不明白为什么程序的行为如此奇怪,我想知道一个可能导致挂起的场景


public class ProducerConsumer { 

    public static void main(String[] args) {
        Buffer buffer = new Buffer(7);  
        Producer producer = new Producer(buffer);
        Consumer consumer = new Consumer(buffer);

        producer.start();
        consumer.start();
    }
}

class Buffer{ 
    private char [] buffer;
    private int count = 0, in = 0, out = 0;

    private final Object object1 = new Object(); 

    Buffer(int size){
        buffer = new char[size];
    }

    public void put (char c) {
        while(count == buffer.length) ;

        synchronized(object1) { 
            System.out.println("Producing" + c + "...");
            buffer[in] = c;
            in = (in + 1) % buffer.length;
            count++;    
        }
    }

    public char get() {
        while(count == 0) ;  
        char c = buffer[out];

        synchronized(object1) {
            out = (out + 1) % buffer.length;
            count--;
            System.out.println("Consuming" + c + "...");
            }
        return c;
    }
}

class Producer extends Thread {
    private Buffer buffer;

    Producer(Buffer b){
        buffer = b;
    }

    public void run() {
        for(int i = 0; i < 10; i++) {
            buffer.put((char) ('A' + i%26 ));
        }
    }
}

class Consumer extends Thread {
    private Buffer buffer;

    Consumer(Buffer b){
        buffer = b;
    }

    public void run() {
        for(int i = 0; i < 10; i++) {
            buffer.get();
        }
    }
}

公共类生产者消费者{
公共静态void main(字符串[]args){
缓冲区=新缓冲区(7);
生产者=新生产者(缓冲区);
消费者=新消费者(缓冲区);
producer.start();
consumer.start();
}
}
类缓冲区{
私有字符[]缓冲区;
私有整数计数=0,输入=0,输出=0;
私有最终对象object1=新对象();
缓冲区(整数大小){
缓冲区=新字符[大小];
}
公开作废认沽期权(字符c){
while(count==buffer.length);
已同步(对象1){
System.out.println(“产生“+c+”);
缓冲区[in]=c;
in=(in+1)%buffer.length;
计数++;
}
}
公共字符get(){
而(计数=0);
char c=缓冲区[out];
已同步(object1){
out=(out+1)%buffer.length;
计数--;
系统输出打印项次(“消耗”+c+”);
}
返回c;
}
}
类生成器扩展线程{
专用缓冲区;
生产商(缓冲区b){
缓冲区=b;
}
公开募捐{
对于(int i=0;i<10;i++){
put((char)('A'+i%26));
}
}
}
类使用者扩展线程{
专用缓冲区;
耗电元件(缓冲器b){
缓冲区=b;
}
公开募捐{
对于(int i=0;i<10;i++){
buffer.get();
}
}
}
这是程序输出及其线程转储

c:\Temp\tt>java ProducerConsumer
ProducingA...
ConsumingA...
ProducingB...
ConsumingB...
ProducingC...
ConsumingC...
ProducingD...
ConsumingD...
ProducingE...
ConsumingE...
ProducingF...
ConsumingF...
ProducingG...
ConsumingG...
ProducingH...
ConsumingH...
ProducingI...
ProducingJ...
2019-12-08 22:28:51
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.231-b11 mixed mode):

"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000002761800 nid=0x3990 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" #12 prio=5 os_prio=0 tid=0x000000003a12a800 nid=0x36f0 runnable [0x000000003b04f000]
   java.lang.Thread.State: RUNNABLE
        at Buffer.get(ProducerConsumer.java:36)
        at Consumer.run(ProducerConsumer.java:71)

"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x000000003a0ff000 nid=0x30a4 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #9 daemon prio=9 os_prio=2 tid=0x000000003a05a000 nid=0x3890 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x000000003a057000 nid=0x16a4 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x000000003a055000 nid=0x4b4 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000000003a04d800 nid=0x4160 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000039ff9000 nid=0x1028 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000039ff7800 nid=0x4f80 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000039fe1800 nid=0x21c in Object.wait() [0x000000003a5be000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000066c408ed8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
        - locked <0x000000066c408ed8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000039fe0800 nid=0x4588 in Object.wait() [0x000000003a4bf000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000066c406c00> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x000000066c406c00> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=2 tid=0x00000000381e9800 nid=0x5418 runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002776800 nid=0x2580 runnable

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002778000 nid=0x4c98 runnable

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000277a000 nid=0x560c runnable

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000277b800 nid=0x3e78 runnable

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x000000000277d800 nid=0x1f24 runnable

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000002780000 nid=0x5074 runnable

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000002783000 nid=0x3d88 runnable

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000002784000 nid=0x4d18 runnable

"VM Periodic Task Thread" os_prio=2 tid=0x000000003a11c800 nid=0x3f8c waiting on condition

JNI global references: 5

Heap
 PSYoungGen      total 304640K, used 31335K [0x000000066c400000, 0x0000000681800000, 0x00000007c0000000)
  eden space 261120K, 12% used [0x000000066c400000,0x000000066e299c00,0x000000067c300000)
  from space 43520K, 0% used [0x000000067ed80000,0x000000067ed80000,0x0000000681800000)
  to   space 43520K, 0% used [0x000000067c300000,0x000000067c300000,0x000000067ed80000)
 ParOldGen       total 696320K, used 0K [0x00000003c4c00000, 0x00000003ef400000, 0x000000066c400000)
  object space 696320K, 0% used [0x00000003c4c00000,0x00000003c4c00000,0x00000003ef400000)
 Metaspace       used 2642K, capacity 4492K, committed 4864K, reserved 1056768K
  class space    used 283K, capacity 388K, committed 512K, reserved 1048576K


c:\Temp\tt>java产品消费者
生产。。。
消费。。。
生产B。。。
消费。。。
生产。。。
消费。。。
生产。。。
消耗。。。
生产。。。
消费。。。
生产。。。
消费。。。
生产。。。
消耗。。。
生产。。。
消耗。。。
生产。。。
生产j。。。
2019-12-08 22:28:51
全线程转储Java热点(TM)64位服务器VM(25.231-b11混合模式):
“DestroyJavaVM”#13优先级=5 os_优先级=0 tid=0x0000000002761800 nid=0x3990等待条件[0x0000000000000000]
java.lang.Thread.State:可运行
“线程1”#12优先级=5操作系统优先级=0 tid=0x000000003a12a800 nid=0x36f0可运行[0x000000003b04f000]
java.lang.Thread.State:可运行
get(ProducerConsumer.java:36)
运行(ProducerConsumer.java:71)
“服务线程”#10守护进程优先级=9 os_优先级=0 tid=0x000000003a0ff000 nid=0x30a4可运行[0x0000000000000000]
java.lang.Thread.State:可运行
“C1编译器线程3”#9守护进程优先级=9 os_优先级=2 tid=0x000000003a05a000 nid=0x3890等待条件[0x0000000000000000]
java.lang.Thread.State:可运行
“C2编译器线程2”#8守护进程优先级=9 os_优先级=2 tid=0x000000003a057000 nid=0x16a4等待条件[0x0000000000000000]
java.lang.Thread.State:可运行
“C2编译器线程1”#7守护进程优先级=9 os_优先级=2 tid=0x000000003a055000 nid=0x4b4等待条件[0x0000000000000000]
java.lang.Thread.State:可运行
“C2编译器线程0”#6守护进程优先级=9 os_优先级=2 tid=0x000000003a04d800 nid=0x4160等待条件[0x0000000000000000]
java.lang.Thread.State:可运行
“附加侦听器”#5守护进程优先级=5 os_优先级=2 tid=0x0000000039ff9000 nid=0x1028可运行[0x0000000000000000]
java.lang.Thread.State:可运行
“信号分配器”#4守护进程优先级=9 os_优先级=2 tid=0x0000000039ff7800 nid=0x4f80等待条件[0x0000000000000000]
java.lang.Thread.State:可运行
对象中的“终结器”#3守护进程优先级=8 os_优先级=1 tid=0x0000000039fe1800 nid=0x21c。等待()[0x000000003a5be000]
java.lang.Thread.State:正在等待(在对象监视器上)
在java.lang.Object.wait(本机方法)
-等待(java.lang.ref.ReferenceQueue$Lock)
位于java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
-锁定(java.lang.ref.ReferenceQueue$Lock)
位于java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
位于java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
对象中的“引用处理程序”#2守护进程优先级=10 os_优先级=2 tid=0x0000000039fe0800 nid=0x4588。等待()[0x000000003a4bf000]
java.lang.Thread.State:正在等待(在对象监视器上)
在java.lang.Object.wait(本机方法)
-等待(java.lang.ref.Reference$Lock)
在java.lang.Object.wait(Object.java:502)
位于java.lang.ref.Reference.tryHandlePending(Reference.java:191)
-锁定(一个java.lang.ref.Reference$Lock)
在java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
“VM线程”os_prio=2 tid=0x00000000381e9800 nid=0x5418可运行
“GC任务线程0(并行GC)”os_prio=0 tid=0x0000000002776800 nid=0x2580可运行
“GC任务线程1(并行GC)”os_prio=0 tid=0x0000000002778000 nid=0x4c98可运行
“GC任务线程2(并行GC)”os_prio=0 tid=0x000000000277a000 nid=0x560c可运行
“GC任务线程3(并行GC)”os_prio=0 tid=0x000000000277b800 nid=0x3e78可运行
“GC任务线程4(并行GC)”os_prio=0 tid=0x000000000277d800 nid=0x1f24可运行
“GC任务线程5(并行GC)”os_prio=0 tid=0x0000000002780000 nid=0x5074可运行
“GC任务线程6(并行GC)”os_prio=0 tid=0x0000000002783000 nid=0x3d88可运行
“GC任务线程7(并行GC)”os_prio=0 tid=0x0000000002784000 nid=0x4d18可运行
“VM定期任务线程”os_prio=2 tid=0x000000003a11c800 nid=0x3f8c等待状态
JNI全球参考:5
堆
PSYoungGen总计304640K,使用31335K[0x000000066c400000,0x0000000681800000,0x00000007c0000000)
eden空间261120K,已使用12%[0x000000066c400000,0x000000066e299c00,0x000000067c300000)
从…起
Buffer buffer = new Buffer(7);
Producer producer = new Producer(buffer);
Consumer consumer = new Consumer(buffer);

consumer.start();
Thread.sleep(2000);
producer.start();
class Buffer{
        private char [] buffer;
        private int count = 0, in = 0, out = 0;

        private final Object object1 = new Object();

        Buffer(int size){
            buffer = new char[size];
        }

        public void put (char c) throws InterruptedException {
            //while(count == buffer.length) ;

            synchronized(object1) {
                if(count == buffer.length){
                    object1.wait();
                }
                System.out.println("Producing" + c + "...");
                buffer[in] = c;
                in = (in + 1) % buffer.length;
                count++;
                object1.notify();
            }
        }

        public char get() throws InterruptedException {
            //while(count == 0) ;

            while (true){
                synchronized(object1) {
                    if(count == 0){
                        object1.wait();
                    }
                    char c = buffer[out];
                    out = (out + 1) % buffer.length;
                    count--;
                    System.out.println("Consuming" + c + "...");
                    object1.notify();
                    return c;
                }

            }

        }
    }