java同步中,为什么要wait,又notify谁?

2024-12-24 16:58:09
推荐回答(2个)
回答1:

对象锁与同步块或者实例同步方法相关系,但如果线程进入静态同步方法,就必须获得类锁。用锁只能达到这样的目的:使得一个任务不会干涉另一个任务的资源,保证在任何时刻都只有一个任务可以访问某个资源。但两个任务要协同作战,互相通信,要一起工作去解决某个问题,必须使他们友好握手、共商国事。这种机制靠Object的方法wait()和notify()来安全地实现。在Thread对象上调用wait()方法将释放线程所有的锁定,这种说法是错误的。Thread类对象也是对象也有wait()方法,它释放的只是它自己作为线程对象的锁,这在线程池的概念级上理解。 似乎理解起来,wait()是自己停止,等待被唤醒;notify()也是自己停止,通知别人。那么感觉没什么大的区别,不急,先仔细分析他们的来历。wait()通常线程要执行下去需要等待某个条件发生变化,但改变这个条件已经超出了当前方法的控制能力。通常,这种条件由另一个任务来改变。既然执行不下去,傻等,又改变不了现实,那还不如交出执行权,令当前线程挂起,同步资源解锁,使别的线程可以访问并修改共享资源,自己进行排队队列,等候别人的通知。经过测试,好象是先入后出的顺序被唤醒的。释放了锁意味着另一个任务可以获得这个锁,这一点至关重要,因为这些其他的方法再入处理通常会引起wait()感兴趣的变化。wait()和notify()必须包括在synchronized代码块中,等待中的线程必须由notify()方法显式地唤醒,否则它会永远地等待下去。很多人初级接触多线程时,会习惯把wait()和notify()放在run()方法里,一定要谨记,这两个方法属于某个对象,应在对象所在的类方法中定义它,然后run中去调用它。 这里不得不提下,在Object的wait方法是重载的。有三个方法,了解一下除无参之外的另一个方法wait(毫秒数 n); 这里毫秒数是指,如果没有notify通知的情况下,当前被wait线程,经过n毫秒之后依然可以回到可运行状态。如果参数为零,则不考虑实际时间,在获得通知前该线程将一直等待。wait(0, 0) 与 wait(0) 相同。 notify()唤醒正在队列中等待资源的优先级最高的线程。但它自己不马上退出资源,继续执行,等全部执行完了,退出,释放锁,这样才让wait()的线程进入。所以说在对象(当前线程具有其锁定)调用notify()方法一定释放锁定是只是一厢情愿的。至于与notifyAll()区别,后者更加安全。使用notify(),在众多等待同一个锁的任务中只有一个会被唤醒,因此如果你希望使用notify(),就必须保证被唤醒的是恰当的任务。notify()也就是this.notify(),唤醒所有争抢自己的线程,与别的对象产生的wait()没有关系。 synchronized (a) {
System.out.println("notify");
a.notifyAll(); //假如这里是wait(),下句代码就暂时不会执行!
System.out.println("continue"); //notifyAll()以后,这句代码还是要执行的
} 我曾经自己写过如下非常幼稚的代码,写在public void run()里边,目的是在zoneRectangleSize < 1的情况下,使自己的线程处于阻塞状态,虽然不会出错,但这个wait调用的是线程类对象本身的wait(),毕竟它也是来自Object,所以肯定达不到预期的效果: synchronized (mainApp) {
} Thread的静态方法sleep()是不释放锁的,也不用操作锁,所以可以在非同步控制方法和run方法内部调用。也就是说当前线程即使进入sleep状态也抱着这把锁睡觉,保持高度的监控状态,即使其它线程在外边踢门叫嚷骂娘,他是心安理得,坚决不释放。如果一直昏睡下去,拥有同一对象资源的线程们都会玩完的。

回答2:

  在多线路程中经常用到。
  当在一个线程A中执行 wait()后,这个线程就会处于等待状态。
  如果想重新激活线程A,继续向下执行代码,就必须在另一个线程中来激活线程A
  class A extends Thread
  {
  public void run()
  {
  wait();
  System.out.println("end");
  }
  public synrhonized void abc()
  {
  notify();
  }
  }
  class B extends Therad
  {
  public void run()
  {
  synchronized(A){A.notify()}; //激活
  或
  A.abc(); //激活
  }
  }
  上面的代码只是一个形式。