Java嵌套监视器(克服明显的死锁)

时间:2019-11-16 19:22:38

标签: java multithreading monitor

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

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

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

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();       
    }
}

1 个答案:

答案 0 :(得分:1)

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

需要成为

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

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