Java 线程wait()之后一定要notify()才能唤醒吗?

在java方法定义上有:

 void notify() 
          唤醒在此对象监视器上等待的单个线程。 
 void notifyAll() 
          唤醒在此对象监视器上等待的所有线程。 
 void wait() 

          导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。

特别地,以上方法只能在同步方法或同步块内部调用,且只能由被同步的资源对象调用。如果当前线程不是对象所得持有者,或者不是被同步的对象调用,以上方法抛出一个java.lang.IllegalMonitorStateException 异常。


下面先看一个例子:

package test;

public class WaitTest { 
	static public String aString="";
    public static void main(String[] args) {  
       ThreadA t1 = new ThreadA("t1"); 
    	
    	synchronized(WaitTest.aString){
            try {
            	t1.start();
            	System.out.println("线程t1的状态是:"+t1.isAlive());
            	System.out.println("挂起主线程...");
            	WaitTest.aString.wait();
            	System.out.println("在挂起线程后面的输出");
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}

    }  
} 
class ThreadA extends Thread{  
    public ThreadA(String name) {  
        super(name);  
    }  
    public void run() {  
        synchronized (WaitTest.aString) {  
            try {                         
                Thread.sleep(1000); //  使当前线阻塞 1 s,确保主程序的 wait()执行之后再执行 notify()  
            } catch (Exception e) {  
                e.printStackTrace();  
            }             
            //System.out.println(Thread.currentThread().getName()+" call notify()");  
            // 唤醒当前的wait线程  
            //WaitTest.aString.notify();  
        }  
    }  
}

输出结果:

线程t1的状态是:true
挂起主线程...

上述结果把WaitTest.sString.notify()这段注释掉之后,挂起主线程后,主线程的WaitTest.sString.wait()后面的代码无法继续执行下去,程序不退出,无限期等待,因此,在线程wait()之后,是需要被唤醒才能执行后续代码的。


再看一个例子:

package test;

public class WaitTest2 { 
    public static void main(String[] args) {  
       ThreadA t1 = new ThreadA("t1"); 
        synchronized(t1) {  
            try {  
                // 启动“线程t1”  
                System.out.println(Thread.currentThread().getName()+" start t1");  
                t1.start();  
                // 主线程等待t1通过notify()唤醒。  
                System.out.println("挂起主线程"); 
                System.out.println("线程t1的状态是:"+t1.isAlive());
                t1.wait();  //  不是使t1线程等待,而是让拥有t1这个对象的主线程等待
                System.out.println("挂起主线程后面的输出");  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        } 

    }  
} 
class ThreadA extends Thread{  
    public ThreadA(String name) {  
        super(name);  
    }  
    public void run() {  
        synchronized (this) {  
            try {                         
                Thread.sleep(1000); //  使当前线阻塞 1 s确保在主线程wait()之前t1没有执行完并退出 
            } catch (Exception e) {  
                e.printStackTrace();  
            }             
            //System.out.println(Thread.currentThread().getName()+" call notify()");  
            // 唤醒当前的wait线程  
            //this.notify();  
        }  
    }  
}

输出结果:

main start t1
挂起主线程
线程t1的状态是:true
挂起主线程后面的输出

在上面的例子中,同样是把notify()这个方法注释掉了,但是主线程wait()后面的代码还是可以得到执行,这说明了t1.wait()运行后,不需要t1.notify()能够唤醒!

线程正常结束后,会使以这个线程对象运行的wait()等待,退出等待状态!而如果在运行wait()之前,线程已经结束了,则这个wait就没有程序唤醒了,例如如果上述不睡1秒的话,在主线程的t1.wait()执行之前就运行完毕退出那么主线程就无法被唤醒了。

实际上,Thread源码里面的join()方法也是使用这种机制:

原码里的join()方法,实际上就是运行的 wait(). 需要运行join的线程运行join方法,实际上是在此线程上调用了需要加入的线程对象的wait()方法,加入的线程运行完后,自然从wait退出了。

结论:

线程对象的wait()方法运行后,可以不用其notify()方法退出,会在线程结束后,自动退出。

猜你喜欢

转载自blog.csdn.net/deronn/article/details/80450959
今日推荐