为什么ThreadA线程在主线程调用wait()方法前就已经执行完同步块并释放了锁,主线程就无法等待ThreadA线程的通知,
时间: 2024-04-01 19:37:57 浏览: 5
这个问题涉及到Java中的线程同步机制。当一个线程调用了一个对象的wait()方法时,它会释放该对象持有的锁,并且进入该对象的等待队列中,等待其他线程通过notify()或notifyAll()方法来唤醒它。在此期间,其他线程可以获得该对象的锁并执行同步块。
如果ThreadA线程在主线程调用wait()方法前就已经执行完同步块并释放了锁,那么主线程将无法等待ThreadA线程的通知。因为此时主线程还没有进入等待队列,它仍然持有该对象的锁,而ThreadA线程已经释放了锁并进入等待队列中。
因此,在使用wait()和notify()或notifyAll()方法时,必须确保线程在等待通知之前持有锁,并在通知之后释放锁,以便其他线程可以访问该对象。
相关问题
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()方法通知主线程,主线程也无法得到通知,因为主线程已经错过了等待的时间,无法再次等待。所以主线程就无法输出“我还是执行了”。
package Unit4; class ThreadA extends Thread{ public int num = 0; public void run(){ synchronized (this){ //在此类对象上实现同步,this 指代当前对象 for (int i= 0;i<3;++i) this.num += i; notifyAll();//通知所有在这个对象是等待的线程开始执行,在这里就是通知 TestNotify //主线程开始执行 } } public int getNum(){ return this.num; } } public class TestNotify extends Thread{ public static void main(String[] args) { ThreadA threada = new ThreadA(); threada.start(); //threada 线程有执行资格,但是还没有开始执行 synchronized (threada){ try { threada.wait(); //主线程等待 threada 线程执行结束才开始执行 // 而且只有获得了当前 threada 对象的锁之后才能执行 wait,就是说在同步域内才可以执行wait, //执行wait 后放弃对象锁 }catch (InterruptedException e){ e.printStackTrace(); } } System.out.println(threada.getNum()); } }
这段代码是一个简单的线程同步的例子,其中包括 ThreadA 和 TestNotify 两个类。
ThreadA 继承了 Thread 类,并且实现了 run 方法。在 run 方法中,使用 synchronized(this) 实现了对当前对象的同步。该同步块中使用 for 循环累加了 num 变量的值,并在循环结束后使用 notifyAll() 方法通知所有等待在该对象上的线程继续执行。
TestNotify 类中的 main 方法中,首先实例化了一个 ThreadA 对象 threada,并且调用了它的 start 方法启动线程。接着,在 synchronized 块中调用了 threada 的 wait 方法,使得主线程等待 threada 线程执行结束后才开始执行。最后,输出 threada.getNum() 的值。
这段代码的作用是实现了对线程的同步控制,确保了线程的执行顺序。