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

主线程创建两个线程t1和t2,这些线程的run()方法创建两个新线程c1和c2。我想要一个方案,直到t1的c1&c2处于活动状态,t2才会开始执行。
在我的代码中,notify和wait导致运行时异常。由于它们不在同步块中,该怎么办?

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()。调用notify时无法获得同一监视器。

根据我的理解,线程t1和t2在这里没有访问它们的公共对象,因此我们应该传递同步锁来调用wait()和notify()的对象是什么?

参考方案

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

编辑
因为您不能使用连接,所以我建议您使用CountDownLatch
其文档指出:

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

您要的是哪个。

第二编辑

这是代码的修改版本,该代码使用HomeMade 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();
    }       
}

Java-搜索字符串数组中的字符串 - java

在Java中,我们是否有任何方法可以发现特定字符串是字符串数组的一部分。我可以避免出现一个循环。例如String [] array = {"AA","BB","CC" }; string x = "BB" 我想要一个if (some condition to tell wheth…

Java RegEx中的单词边界\ b - java

我在使用\b作为Java Regex中的单词定界符时遇到困难。对于text = "/* sql statement */ INSERT INTO someTable"; Pattern.compile("(?i)\binsert\b");找不到匹配项Pattern insPtrn = Pattern.compile(&…

Java Double与BigDecimal - java

我正在查看一些使用双精度变量来存储(360-359.9998779296875)结果为0.0001220703125的代码。 double变量将其存储为-1.220703125E-4。当我使用BigDecimal时,其存储为0.0001220703125。为什么将它双重存储为-1.220703125E-4? 参考方案 我不会在这里提及精度问题,而只会提及数字…

Java:线程池如何将线程映射到可运行对象 - java

试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …

JAVA:字节码和二进制有什么区别? - java

java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…