class ThreadA2 extends Thread { public int num = 0; public void run() { System.out.println(getName()); synchronized (this) { for (int i = 0; i < 3; ++i) this.num += i; } } public int getNum() { return this.num; } } public class TestNotify2 extends Thread { public static void main(String[] args) { ThreadA2 thread = new ThreadA2(); thread.start(); synchronized (thread){ try { thread.wait(); }catch (InterruptedException e){ e.printStackTrace(); } } } }代码为什么主线程没有被通知确还是执行了
时间: 2024-04-02 13:31:35 浏览: 46
在主线程中使用了 `wait()` 方法,这会使主线程进入等待状态,并释放对 `thread` 对象的锁。当 `thread` 对象调用 `notify()` 方法时,会通知正在等待 `thread` 对象锁的线程(即主线程)继续执行,但是在此之前,`thread` 对象的锁已经被释放,所以主线程并没有被通知而继续执行了。要想主线程能够被通知到,可以在主线程中使用一个标志位来判断是否被通知,或者使用 `notifyAll()` 方法来通知所有等待的线程。
相关问题
class ThreadA extends Thread{ public int num = 0; public void run(){ synchronized (this){ //在此类对象上实现同步,this 指代当前对象 for (int i= 0;i<3;++i) this.num += i; try { Thread.sleep(1000); //如果ThreadA的三个示例线程在还没有进入等待状态之前就受到了notifyAll的信号 //那将会发生严重后果,因为调用notifyAll的线程只可以调用一次notifyAll,那将会造成等待 //的线程永远等待下去 //所以在此处让它小睡一会,让其他线程有时间进入等待状态 }catch (InterruptedException e){ e.printStackTrace(); } notifyAll();//通知所有在这个对象是等待的线程开始执行,在这里就是通知 TestNotify //主线程开始执行 } } public int getNum(){ return this.num; } } class ThreadB extends Thread{ private ThreadA threada; public ThreadB (ThreadA ta){ this.threada = ta; } public void run(){ System.out.println(Thread.currentThread().getName()+" is waiting."); synchronized (threada){ try { threada.wait(); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" "+this.threada.getNum()); } } } public class TestNotify extends Thread{ public static void main(String[] args) { ThreadA threada = new ThreadA(); new ThreadB(threada).start(); new ThreadB(threada).start(); new ThreadB(threada).start(); threada.start(); } }
这段代码涉及多线程同步和通信,其中ThreadA是一个线程类,num是一个公共变量,run()方法中使用了synchronized语句块来实现同步,notifyAll()方法来通知所有等待在该对象上的线程,getnum()方法用来返回num的值。ThreadB是另一个线程类,其构造方法接受一个ThreadA对象,run()方法中使用了synchronized语句块和wait()方法来实现等待状态,直到ThreadA调用notifyAll()方法后才开始执行,并调用ThreadA的getNum()方法获取num的值。TestNotify类是主类,创建了一个ThreadA对象和三个ThreadB对象,并启动这些线程。
class ThreadA extends Thread { public int num = 0; public void run() { synchronized (this) { for (int i = 0; i < 3; ++i) this.num += i; System.out.println(getName()); notifyAll(); } } public int getNum() { return this.num; } } /* 在ThreadA线程中,我们使用了synchronized关键字来锁住对象,并在其中进行了运算, 但是没有调用notify()或notifyAll()方法唤醒其他等待该对象锁的线程。 在主线程中,我们使用synchronized关键字锁住了ThreadA对象,并调用了wait()方法等待该对象的锁。 当ThreadA线程执行完同步块中的运算后,释放了该对象锁,主线程获得了该对象锁并继续执行,输出了“我还是执行了”。 这里需要注意的是,主线程获得了ThreadA对象锁后,才能输出“我还是执行了”。(但是一般情况都是主线程先执行,所以很大概率主线程会先调用wait()方法) 如果ThreadA线程在主线程调用wait()方法前就已经执行完同步块并释放了锁, 那么主线程就无法等待ThreadA线程的通知,也就无法输出“我还是执行了”。 */ public class TestNotify extends Thread { public static void main(String[] args) throws InterruptedException{ ThreadA threada = new ThreadA(); threada.start(); Thread.sleep(2000); //在外面加入sleep就输出不了了,而且会错过通知,导致一直等待 synchronized (threada){ try { // Thread.sleep(2000);//在里面不行,因为睡醒后执行wait(),此时锁是空闲的又自动获取了 threada.wait(); System.out.println("我还是执行了"); }catch (InterruptedException e){ e.printStackTrace(); } } System.out.println(threada.getNum()); } }代码为什么ThreadA线程在主线程调用wait()方法前就已经执行完同步块并释放了锁, 那么主线程就无法等待ThreadA线程的通知,也就无法输出“我还是执行了”。
这是因为在主线程调用wait()方法之前,ThreadA线程已经执行完同步块中的运算,并释放了该对象锁。主线程调用wait()方法后就需要等待ThreadA线程的通知才能继续执行,但是由于ThreadA线程已经释放了对象锁,所以即使ThreadA线程在此后调用notify()或notifyAll()方法通知主线程,主线程也无法得到通知,因为主线程已经错过了等待的时间,无法再次等待。所以主线程就无法输出“我还是执行了”。
阅读全文