如何在调用 notifyAll() 时获得相同的监视器



主线程创建两个线程 t1 和 t2 run() 方法,这些线程创建两个新线程 c1 和 c2。我想要一个场景,直到c1&c2(的t1)还活着,t2不会开始执行。在我的代码中,通知和等待导致运行时异常。由于它们不在同步块中,如何做到这一点?

public class childTcreat2newthread {
    public static void main(String[] args) throws InterruptedException {
        Thread mainT=Thread.currentThread();
        Target ra=new Target("a");
        Thread t1=new Thread(ra);
        t1.start();
        t1.join();
        while(ra.getC1().isAlive()==true||ra.getC2().isAlive()==true){
        synchronized (mainT) {
        mainT.wait();
        }}
        new Thread(new Target("b")).start();}}

class Target implements Runnable{
    Thread c1=new Thread(new Target1("1"));
    Thread c2=new Thread(new Target1("2"));
    String msg;
    Target(String msg){
        this.msg=msg;
    }
    @Override
    public void run() {

        for(int j=0;j<100000;j++){
            for(int i=0;i<10000;i++){
                if(i%10000==0&&j%10000==0){System.out.print(msg);}
            }}
        t1.start();
        t2.start();
    }
    public Thread getC1(){return c1;}
    public Thread getC2(){return c2;}
}
class Target1 implements Runnable   {
    String msg;
    Target1(String msg){
        this.msg=msg;
    }
    @Override
    public synchronized void run() {
        for(int j=0;j<100000;j++){
            for(int i=0;i<100000;i++){
                if(i%100000==0&&j%10000==0){System.out.print(msg);}
            }
        }
        try{
        notifyAll();
        System.out.println("K");}catch(IllegalMonitorStateException e){System.out.println("nIllegalMonitorStateException!! in "+msg+"n");}
    }
}

wait( ) 告诉调用线程放弃监视器并进入睡眠状态,直到其他线程进入同一监视器并调用 notify( )。呼叫通知时无法获得相同的监视器。怎么做?

至于我的理解,线程 t1 和 t2 在这里都没有它们正在访问的公共对象,所以我们应该在同步锁中传递哪个对象来调用 wait() 和 notify()?

正如

@JB Nizet指出的那样,你应该使用join来等待线程终止

编辑由于您不能使用join,因此建议您使用CountDownLatch,因为其文件指出:

一种同步辅助工具,它允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。

这就是你要求的。

第二次编辑

下面是代码的修改版本,它使用使用等待和通知的自制 CountDownLatch 等待线程终止。

    import java.util.concurrent.CountDownLatch;
public class childTcreat2newthread {
    public static void main(String[] args) throws InterruptedException {
        MyCountDownLatch doneSignal = new MyCountDownLatch(2);
        Target ra = new Target("a",doneSignal);
        Thread t1 = new Thread(ra);
        t1.start();
        doneSignal.await();
        System.out.println("after await ");
        MyCountDownLatch doneSignal1 = new MyCountDownLatch(2);
        new Thread(new Target("b",doneSignal1)).start();
    }
}
class Target implements Runnable {
    private Thread c1;
    private Thread c2;
    String msg;

    Target(String msg, MyCountDownLatch doneSignal) {
        this.msg = msg;
        c1 = new Thread(new Target1("1",doneSignal));
        c2 = new Thread(new Target1("2",doneSignal));
    }
    @Override
    public void run() {
        System.out.println("Start of Target " + msg);
        for (int j = 0; j < 100000; j++) {
            for (int i = 0; i < 10000; i++) {
                if (i % 10000 == 0 && j % 10000 == 0) {
                    System.out.print(msg);
                }
            }
        }
        c1.start();
        c2.start();
//      try {
//          c1.join();
//          c2.join();
//      } catch (InterruptedException e) {
//          // TODO Auto-generated catch block
//          e.printStackTrace();
//      }
        System.out.println("End of Target " + msg);
    }
    public Thread getC1() {
        return c1;
    }
    public Thread getC2() {
        return c2;
    }
}
class Target1 implements Runnable {
    String msg;
    private MyCountDownLatch doneSignal;
    Target1(String msg, MyCountDownLatch doneSignal) {
        this.msg = msg;
        this.doneSignal=doneSignal;
    }
    @Override
    public void run() {
        System.out.println("Start of Target1 " + msg);
        for (int j = 0; j < 100000; j++) {
            for (int i = 0; i < 100000; i++) {
                if (i % 100000 == 0 && j % 10000 == 0) {
                    System.out.print(msg);
                }
            }
        }
        try {
            System.out.println("K");
            doneSignal.countDown();
            System.out.println("End of Target1 " + msg);
        } catch (IllegalMonitorStateException e) {
            System.out.println("nIllegalMonitorStateException!! in " + msg
                    + "n");
        }
    }
}
class MyCountDownLatch {
    private int waitersNum;
    public MyCountDownLatch(int waitersNum) {
        this.waitersNum=waitersNum;
    }
    public synchronized void countDown() {
        waitersNum--;
        if (waitersNum==0) {
            notifyAll();
        }
    }
    public synchronized void await() throws InterruptedException {
        wait();
    }       
}

通知、通知所有、等待调用应在同一对象的监视器中完成。应该有一个像Object这样的共享对象,你应该围绕它构建你的逻辑。例如:

public class ClassA{
    Object lockObject=new Object(); 
    //Thread A will call this method
    public void  methodA(){
         synchronized(lockObject){
             while(!aCondition)
                 lockObject.wait();
         }
    }
    //Thread B will call this method
    public void  methodB(){
         synchronized(lockObject){
             aCondition=true;
             lockObject.notify();
         }
    }
}

相关内容

最新更新