Java 嵌套监视器(越过明显的死锁)

Java Nested Monitors (moving past apparent deadlock)

我在同一个对象上进行同步和阻塞。每个线程调用 PuppetShow class 中的 testQueue() 方法,该方法为每个要阻塞的线程实例化一个不同的对象。我的问题是,一旦 capacity==0,遇到该条件的第一个线程对其对象调用 wait(),然后程序挂起,没有其他线程运行。第三个线程根据 println 语句输出 "waaah" 然后没有其他行被执行,尽管我在这个线程之后实例化了线程。

如何在 PuppetShow() 的 testQueue 方法中移过 lock.wait() 行 class?

我希望能够阻塞不同的对象并将它们添加到向量中以便对线程组进行排队。这就是为什么我要阻塞不同的对象,然后将它们添加到向量中。为了通知线程,我只是通知向量中某个位置的元素。

import java.util.Vector;

public class PuppetShow {

    private int numSeats = 2;
    private int capacity = numSeats;
    private Vector<Object> attendingPuppetShow = new Vector<Object>();
    public Vector<Object> waitingStudents = new Vector<Object>();

    public void testQueue() {
        Object lock = new Object();
        System.out.println("testQueue begin");
        synchronized(lock) {
            if(testAttending(lock)) {
                try {
                    System.out.println("waaah");
                    lock.wait();
                    System.out.println("ugh");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public synchronized boolean testAttending(Object lock) {
        System.out.println("testAttending");
        boolean status;
        if(capacity==0) {   
            waitingStudents.add(lock);
            System.out.println("capacity="+capacity+" ws size="+waitingStudents.size());
            status = true;
        }
        else {
            capacity--;
            attendingPuppetShow.add(lock);
            System.out.println("capacity="+capacity+" aPS size="+attendingPuppetShow.size());
            status = false;
        }       
        return status;
    }

    public synchronized void testRelease() {        
        if(waitingStudents.size() > 0) {
            while(waitingStudents.size() > 0) {
                synchronized(waitingStudents.elementAt(0)) {
                    waitingStudents.elementAt(0).notify();                  
                }
                waitingStudents.removeElementAt(0);
                capacity++;
            }
        }
    }
}

class GreenStudent extends Thread {

    private PuppetShow ps = new PuppetShow();

    public GreenStudent(int id, PuppetShow ps) {
        setName("GreenStudent-" + id);
        this.ps = ps;
    }

    @Override
    public void run() {     
        System.out.println(getName()+" queuing for show");
            ps.testQueue();
    }
}

class StaffMember extends Thread {

    private PuppetShow ps = new PuppetShow();

    public StaffMember(int id, PuppetShow ps) {
        setName("StaffMember-" + id);
        this.ps = ps;
    }

    @Override
    public void run() {
        ps.testRelease();

    }
}

class Driver {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

         PuppetShow ps = new PuppetShow();
         GreenStudent gs1 = new GreenStudent(1, ps);
         GreenStudent gs2 = new GreenStudent(2, ps);
         GreenStudent gs3 = new GreenStudent(3, ps);

         StaffMember sm = new StaffMember(1,ps);

         gs1.run();
         gs2.run();
         gs3.run();      
         sm.run();       
    }
}

         gs1.run();
         gs2.run();
         gs3.run();      
         sm.run();  

需要

         gs1.start();
         gs2.start();
         gs3.start();      
         sm.start(); 

在您的示例中,run 将由调用线程(主线程)调用。 start 将启动另一个线程,然后最终调用 run