Java多线程系列(4)--线程等待与唤醒

来源:互联网 发布:discuz省市区数据库 编辑:程序博客网 时间:2024/05/29 13:22

一、wait()、notify()、notifyAll()等方法基本概述

在Object.java中,定义了wait()、notify()和notifyAll()等接口。wait()的作用就是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的的锁;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。
上述方法的详细信息如下:
notify() –唤醒在此对象监视器上等待的单个线程;
notifyAll() –唤醒在此对象监视器上等待的所有线程;
wait() —-让当前线程处于“等待(阻塞)状态”。直到其它线程调用此对象的notify()方法或者notifyAll()方法,当前线程被唤醒(进入就绪状态);
wait(long timeout) —-让当前线程处于“等待(阻塞)状态”。直到其它线程调用此对象的notify()方法或者notifyAll()方法,或者超过指定的时间量,当前线程被唤醒(进入就绪状态);
wait(long timeout,int nanos) —-让当前线程处于“等待(阻塞)状态”。直到其它线程调用此对象的notify()方法或者notifyAll()方法,或者超过指定的时间量,或者其它某个线程中断当前线程,当前线程被唤醒(进入就绪状态)
二、wait()、notify()、notifyAll()代码实例
由于与wait配合起来使用时,notify()和notifyAll()并无太大区别。下面仅通过wait与notify()代码来进行演示

package Test;/** * Created by LKL on 2017/2/20. */public class TestWaitAndNotify {    public static void main(String[] args) throws InterruptedException {        MyThread3 t1 = new MyThread3("t1");     //   MyThread3 t2 = new MyThread3("t2");        synchronized(t1){            System.out.println(Thread.currentThread().getName()+" start t1");         //   System.out.println(Thread.currentThread().getName()+" start t2");            t1.start();         //   t2.start();            //主线程等待t1通过notify()唤醒            System.out.println(Thread.currentThread().getName()+" wait() ");            t1.wait();            //此时持有t1这个对象的锁的是object            System.out.println(Thread.currentThread().getName()+" continue ");        }    }}package Test;/** * Created by LKL on 2017/2/20. */public class MyThread3 extends Thread{    public MyThread3(String name) {        super(name);    }    public void run(){        synchronized(this){            System.out.println(Thread.currentThread().getName()+" call notify()");            //唤醒当前线程            notify();        }    }}

运行结果如下:

main start t1main wait() t1 call notify()main continue 

上述流程为:
(1)主线程main通过new MyThread3(“t1”)新建线程t1,接着通过synchronized(t1)获取”获取t1对象的同步锁”,然后调用t1.start()启动线程t1。
(2)主线程main执行t1.wait()释放”t1对象的锁”,并且进入了等待(阻塞)状态。等待t1对象上的线程通过notify()或notifyAll()将其唤醒。
(3)线程t1运行之后,通过synchronized(this)获取”当前对象的锁”;接着调用notify()唤醒”当前对象上的得带线程”,此时也就意味着唤醒主线程;
(4)线程t1运行完毕之后,会释放当前对象的锁,接着,主线程获取t1对象的锁,然后接着运行。
当把上述代码修改如下时:

package Test;/** * Created by LKL on 2017/2/20. */public class TestWaitAndNotify {    public static void main(String[] args) throws InterruptedException {        MyThread3 t1 = new MyThread3("t1");     //   MyThread3 t2 = new MyThread3("t2");        synchronized(t1){            System.out.println(Thread.currentThread().getName()+" start t1");         //   System.out.println(Thread.currentThread().getName()+" start t2");         //   t1.start();         //   t2.start();            //主线程等待t1通过notify()唤醒            System.out.println(Thread.currentThread().getName()+" wait() ");            t1.wait();            //此时持有t1这个对象的锁的是object            System.out.println(Thread.currentThread().getName()+" continue ");        }    }}

也就是不开启t1这个线程,此时主线程main运行了t1.wait()后,一直处于阻塞状态,因为并没有线程将它唤醒。

main start t1main wait() 

二、wait()、notify()总结

wait()会使当前线程等待,因为线程进入等待(阻塞)状态,所以线程应该释放它所持有的“同步锁”,否则其它线程获取不到这个“同步锁”而无法运行。
notify()和wait()直接就是依据“对象的同步锁”关联起来的。
假设我们把负责唤醒等待线程的那个线程称为唤醒线程,它只有在获取“该对象的同步锁”,此时的同步锁必须和等待线程的同步锁是同一个,并且调用notify()或调用notifyAll()方法之后,才能唤醒等待线程;但是它不能立刻执行,因为唤醒线程还持有该对象的同步锁,必须等到唤醒线程释放了对象的同步锁之后,等待线程才能获取到对象的同步锁,从而继续运行。
因此,notify()和wait()依赖于同步锁,而同步锁是对象所持有,并且每个对象只有一个。所以,wait()、notify()等方法定义在object类中,而不是Thread类中。

文章只是作为自己的学习笔记,借鉴了网上的许多案例,如果觉得阔以的话,希望多交流,在此谢过…

0 0
原创粉丝点击