wait() notify()notifyAll()简介
这三个方法都是定义在Object里面,wait()的作用是让线程进入等待状态,同时wait也会释放当前线程所持有的锁,而notify和notifyAll的作用是唤醒当前对象上的等待线程,notify是唤醒单个线程,而notifyAll 是唤醒所有线程。
Object中关于等待唤醒的API详细信息如下:
notify() 唤醒在此对象监视器上等待的单个线程
notifyAll() -- 唤醒在此对象监视器上等待的所有线程。
wait() -让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的notifyall,notify方法,当前线程处于就绪状态
wait(long time)-让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的notifyall,notify方法,或者超乎指定时间time,当前线程处于就绪状态
wait(long timeout, int nanos) -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。
wait() notify()示例
package test;
//WaitTest.java的源码
class MyThread1 extends Thread{
public MyThread1(String name) {
super(name);
}
public void run(){
System.out.println(Thread.currentThread().getName()+" is running");
}
};
public class WaitTest {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1("t1");
synchronized(t1) {
// 启动“线程t1”
System.out.println(Thread.currentThread().getName()+" start t1");
t1.start();
// t1.run();
// 主线程等待t1通过notify()唤醒。
System.out.println(Thread.currentThread().getName()+" wait()");
try {
t1.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" continue");
}
}
}
运行结果:
main start t1
main wait()
t1 call notify()
main continue
结果说明;
1,注意图中“主线程”代表的是main线程,“线程t1”代表WaitTest中启动的线程t1,而锁代表t1这个对象的同步锁
2,主线程通过通过 new ThreadA("t1") 新建“线程t1”。随后通过synchronized(t1)获取t1的同步锁,然后通过t1.start()将线程置于就绪状态,(并不是start就能获取CPU启动,在本案例中,此时正在运行main线程,需要等到下面的那句wait以后,main线程进入阻塞状态,t1线程才能开始执行run方法)
3,主线程执行t1.wait()释放t1对象的锁,并且进入等待(阻塞)状态,等待t1对象的线程通过notify 或者notifyAll进行唤醒,(本案例中去除掉notify,程序运行结果也一样,因为只有两个线程,t1和main,t1执行到notify了,相当于t1也执行完了它的run体,它就dead状态了,那锁就会被剩余的线程来争抢,因为剩余的只有main,那肯定就是它获得锁了,所以加不加notify都无所谓,反正main都是能够独占这个锁的。)
4,线程t1运行之后,通过synchronized(this)获取当前对象的锁,接着调用notify()唤醒“当前对象上的等待线程”,也就是唤醒主线程
5,线程t1运行完毕以后,释放当前对象的锁,紧接着,主线程获取t1对象的锁,然后接着运行
问题来了:t1.wait()应该是让“线程t1”等待;但是,为什么却是让“主线程main”等待了呢?
注意:jdk的解释中,说wait()的作用是让“当前线程”等待,而“当前线程”是指正在cpu上运行的线程!
这也意味着,虽然t1.wait()是通过“线程t1”调用的wait()方法,但是调用t1.wait()的地方是在“主线程main”中。而主线程必须是“当前线程”,也就是运行状态,才可以执行t1.wait()。所以,此时的“当前线程”是“主线程main”!因此,t1.wait()是让“主线程”等待,而不是“线程t1”!
wait(long time)与notify()
wait(long timeout)会让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
下面的示例就是演示wait(long timeout)在超时情况下,线程被唤醒的情况。
// WaitTimeoutTest.java的源码
class ThreadA extends Thread{
public ThreadA(String name) {
super(name);
}
public void run() {
System.out.println(Thread.currentThread().getName() + " run ");
// 死循环,不断运行。
while(true)
;
}
}
public class WaitTimeoutTest {
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()唤醒 或 notifyAll()唤醒,或超过3000ms延时;然后才被唤醒。
System.out.println(Thread.currentThread().getName() + " call wait ");
t1.wait(3000);
System.out.println(Thread.currentThread().getName() + " continue");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
main start t1
main call wait
t1 run
main continue
结果说明:
其实和前一个程序结果一样,只是main线程的阻塞时间多了3000ms,
wait()和notifyAll()
通过前面的示例,我们知道 notify() 可以唤醒在此对象监视器上等待的单个线程。
下面,我们通过示例演示notifyAll()的用法;它的作用是唤醒在此对象监视器上等待的所有线程。
public class NotifyAllTest {
private static Object obj = new Object();
public static void main(String[] args) {
ThreadA t1 = new ThreadA("t1");
ThreadA t2 = new ThreadA("t2");
ThreadA t3 = new ThreadA("t3");
t1.start();
t2.start();
t3.start();
try {
System.out.println(Thread.currentThread().getName()+" sleep(3000)");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(obj) {
// 主线程等待唤醒。
System.out.println(Thread.currentThread().getName()+" notifyAll()");
obj.notifyAll();
}
}
static class ThreadA extends Thread{
public ThreadA(String name){
super(name);
}
public void run() {
synchronized (obj) {
try {
// 打印输出结果
System.out.println(Thread.currentThread().getName() + " wait");
// 唤醒当前的wait线程
obj.wait();
// 打印输出结果
System.out.println(Thread.currentThread().getName() + " continue");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
运行结果:
t1 wait
main sleep(3000)
t3 wait
t2 wait
main notifyAll()
t2 continue
t3 continue
t1 continue
结果说明:参考下面的流程图。
(01) 主线程中新建并且启动了3个线程"t1", "t2"和"t3"。
(02) 主线程通过sleep(3000)休眠3秒。在主线程休眠3秒的过程中,我们假设"t1", "t2"和"t3"这3个线程都运行了。以"t1"为例,当它运行的时候,它会执行obj.wait()等待其它线程通过notify()或额nofityAll()来唤醒它;相同的道理,"t2"和"t3"也会等待其它线程通过nofity()或nofityAll()来唤醒它们。
(03) 主线程休眠3秒之后,接着运行。执行 obj.notifyAll() 唤醒obj上的等待线程,即唤醒"t1", "t2"和"t3"这3个线程。 紧接着,主线程的synchronized(obj)运行完毕之后,主线程释放“obj锁”。这样,"t1", "t2"和"t3"就可以获取“obj锁”而继续运行了!
为什么notify(),wait()等方法定义在Object中
Object中的notify,wait方法都会和synchronized一样,会对对象的同步锁进行操作。
wait会让当前线程等待,要让线程进入等待,线程就应该释放他的同步锁。否则其他线程获取不到同步锁也运行不起来
等待线程会被notify或者notifyAll唤醒,那么这两个方法唤醒线程依靠的仍然是同步锁。
负责唤醒线程的那个线程(我们称之为唤醒线程),它只有在获取“对象的同步锁”(这里的同步锁和等待线程的同步锁是同一个),并且调用notify和notifyAll之后,才能唤醒等待线程。在等待线程被唤醒后,也不会立马运行,因为唤醒了线程还持有同步锁才能运行。
、总之,这些方法依赖于同步锁,而同步锁是对象持有的,并且每个对象有且只有一个,这就是为什么这些方法定义在Object类,而不是在Thread类中
原文:http://www.cnblogs.com/skywang12345/p/3479224.html