三、等待与唤醒
在Object.java中,定义了wait(), notify()和notifyAll()等接口。
notify() -- 唤醒在此对象监视器上等待的单个线程。
notifyAll() -- 唤醒在此对象监视器上等待的所有线程。
wait() -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout) -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout, int nanos) -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。
注意:1.wait()和notify()必须在synchronized块里面使用
2.调用wait()和notify()的对象必须与synchronized块锁对象一致。
wait()的作用是让当前线程进入等待状态,同时,wait()也会让出当前线程释放它所持有的锁。而 notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有 的线程。
public class WaitTest { public static void main(String[] args) { final Atest a = new Atest(); Runnable runnable = new Runnable(){ @Override public void run() { a.m1(); } }; /** * 经测试调用wait()方法当前线程会处于等待状态,而且会释放它所持有的锁。 */ Thread t1 = new Thread(runnable); Thread t2 = new Thread(runnable); t1.start(); try { /** * 当t1线程执行完,主线程才能继续执行。 * 如果t1处于等待状态,主线程也无法往下执行,因为t1只是处于等待状态,而未执行完。 */ t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); } } class Atest{ boolean flag = true; public synchronized void m1(){ System.out.println("m1方法开始"+Thread.currentThread()); while(flag){ try { this.wait(10000); // this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } flag = false; } System.out.println("m1方法结束"+Thread.currentThread()); } }
这里说一下Thread类的join()方法:
join() 的作用:让“主线程”等待“该线程”结束之后才能继续运行,这里说的主线程是相对于该线程而言的,并不是指定main线程。
package com.fla.thread; public class NotifyTest { public static void main(String[] args) { final Ntest n = new Ntest(); Runnable run1 = new Runnable(){ @Override public void run() { n.m1(); } }; Thread t1 = new Thread(run1); Thread t2 = new Thread(run1); Thread t3 = new Thread(new Runnable() { @Override public void run() { n.m2(); } }); t1.start(); t2.start(); t3.start(); } } class Ntest { boolean flag = true ; public synchronized void m1(){ System.out.println("m1方法开始"+Thread.currentThread()+",锁对象hashcode:"); while(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("m1方法结束"+Thread.currentThread()+",锁对象hashcode:"); } public synchronized void m2(){ System.out.println("m2方法开始"+Thread.currentThread()+",锁对象hashcode:"); // this.notifyAll(); this.notify(); flag = false ; } }
notify()是唤醒在此对象(与同步块锁对象一致)监视器上等待的单个线程。,而notifyAll()是唤醒在此对象监视器上等待的所有线程。
wait() 和 sleep()的差别:
wait() 让当前线程处于“等待(阻塞)状态”,也会让出当前线程释放它所持有的锁,不占cpu资源。
sleep() 让线程睡眠一段时间,占着cpu进入睡眠,如果在同步代码块里面,也不会释放所持有的锁
这里顺便说一下Thread类的yield()方法。
yield()的作用是让步。它能让当前线程由“运行状态”进入到“就绪状态”,从而让 其它具有相同优先级的等待线程获取执行权;但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是 当前线程又进入到“运行状态”继续运行!