Object 方法介绍


public final native void wait(long timeout) throws InterruptedException;

使当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法,或者经过了指定的时间量。

当前线程必须拥有该对象的监视器。

此方法使当前线程(称为T )将自己置于该对象的等待集中,然后放弃对该对象的任何和所有同步声明。线程T出于线程调度目的而被禁用并处于休眠状态,直到发生以下四种情况之一:

其他一些线程为此对象调用notify方法,而线程T恰好被任意选择为要被唤醒的线程。

其他一些线程为此对象调用notifyAll方法。

其他一些线程中断线程T 。

或多或少已经过了指定的实时时间。但是,如果timeout为零,则不考虑实时时间,线程只是等待直到收到通知。

然后将线程T从该对象的等待集中移除,并重新启用线程调度。然后它以通常的方式与其他线程竞争对象同步的权利;一旦它获得了对象的控制权,它对对象的所有同步声明都会恢复到之前的状态——即,恢复到调用wait方法时的状态。线程T然后从调用wait方法返回。因此,从wait方法返回时,对象和线程T的同步状态与调用wait方法时完全相同。

线程也可以在没有被通知、中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件来防范它,如果条件不满足则继续等待。换句话说,等待应该总是在循环中发生,就像这样:

           synchronized (obj) {

               while ()

                   obj.wait(timeout);

               ... // Perform action appropriate to condition

           }

如果当前线程在等待之前或期间被任何线程中断,则抛出InterruptedException 。在此对象的锁定状态已按上述恢复之前,不会引发此异常。

请注意, wait方法将当前线程放入该对象的等待集中,仅解锁该对象;当前线程可能同步的任何其他对象在线程等待时保持锁定。

此方法只能由作为该对象监视器所有者的线程调用。有关线程可以成为监视器所有者的方式的描述,请参见notify方法。

参数:

timeout – 等待的最长时间(以毫秒为单位)。

抛出:

IllegalArgumentException – 如果 timeout 的值为负。

IllegalMonitorStateException – 如果当前线程不是对象监视器的所有者。

InterruptedException – 如果任何线程在当前线程等待通知之前或期间中断了当前线程。抛出此异常时清除当前线程的中断状态。

public final native void notify();

唤醒正在此对象的监视器上等待的单个线程。如果有任何线程正在等待该对象,则选择其中一个被唤醒。该选择是任意的,并由实施自行决定。线程通过调用其中一个wait方法在对象的监视器上等待。

在当前线程放弃对该对象的锁定之前,被唤醒的线程将无法继续。被唤醒的线程将以通常的方式与可能正在积极竞争以在此对象上同步的任何其他线程竞争;例如,被唤醒的线程在成为下一个锁定该对象的线程时不享有可靠的特权或劣势。

此方法只能由作为该对象监视器所有者的线程调用。线程通过以下三种方式之一成为对象监视器的所有者:

通过执行该对象的同步实例方法。

通过执行在对象上同步的synchronized语句的主体。

对于Class,通过执行该类的同步静态方法。

一次只有一个线程可以拥有一个对象的监视器。

抛出:

IllegalMonitorStateException – 如果当前线程不是此对象监视器的所有者。

wait与notify方法测试样例:


/*
在调用wait方法时,线程必须持有被调用对象的锁,当调用wait方法后,该线程就会释放掉该对象的锁(monitor)
在调用thread的sleep方法时,线程不会释放掉线程对象的锁
关于wait、notify和notifyAll方法的总结:
1.当调用wait方法时,首先需要确保调用了wait方法的线程已经持有了对象的锁
2.当调用wait后,该线程就会释放掉该对象的锁,然后进入到等待状态
3.当线程调用wait后进入到等待状态时,它就可以等待其他线程调用相同对象的notify或者notifyAll方法使得自己被唤醒
4.一旦这个线程被其它线程唤醒后,该线程就会与其他线程一同开始竞争这个对象的锁(公平竞争);
只有当线程重新获取到该对象的锁后,线程才会继续往下执行。
5. 调用wait方法的代码片段必须放到synchronized块或者synchronized方法中,这样才可以确保线程在调用wait
方法前已经获取到了对象的锁
6.当调用对象的notify方法时,它就会随机该对象等待集合中的任意一个线程,当某线程被唤醒后,它就会与其它线程一同竞争
对象的锁
7.当调用对象的notifyAll方法时,它就会该对象等待集合中的所有线程,这些线又会开始竞争对象的锁
8.在某一个时刻,只有一个线程可以拥有对象的锁
*/

public class MyObject {
public static void main(String[] args) throws InterruptedException {
      Object obj = new Object();
    //先要获取对象的锁
      synchronized (obj){
         obj.wait();
      }
   }

   public class MyTest{
   //先获取MyTest对象实例的锁,如果是同一个实例,则该实例的其它的被synchronized修饰的方法暂时得不到执行
public synchronized void method1(){ System.out.println("execute method1"); System.out.println("method1 begin await"); try { wait(); } catch (InterruptedException e) { e.printStackTrace(); }
     //执行完wait方法后就释放锁,其它被synchronized修饰的方法可以开始执行,同时该方法进入该对象的等待队列中,直到被通知后,才继续往下执行。
System.out.println(
"method1 continue");      //通知其它在等待的方法,如method2 notify(); System.out.println("notify method2 continue"); } public synchronized void method2(){ System.out.println("execute method2");
      //通知其它在等待的方法,如method1
notify(); System.out.println(
"notify method1 continue"); System.out.println("method2 begin await");
     //method2进入等待队列,并释放锁。
try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("method2 continue"); } } @Test public void testSameInstanceCallMethod(){ MyTest myTest = new MyTest(); Thread thread1 = new Thread(()->{ myTest.method1(); }); Thread thread2 = new Thread(()->{ myTest.method2(); }); thread1.start(); sleep(1000); thread2.start(); } }

测试结果:

execute method1

method1 begin await

execute method2

notify method1 continue

method2 begin await

method1 continue

notify method2 continue

method2 continue