多线程的wait/notify的使用
Posted IT编程之路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程的wait/notify的使用相关的知识,希望对你有一定的参考价值。
多线程的等待/通知机制使用wait()和notify()来实现,两者缺一不可,并且要用在同步方法或者同步代码块中。如果只有使用wait不使用notify的话线程代码就会永远等待下去这样程序就会停止不前,不继续向下运行了。wait使线程停止运行,而notify使停止的线程继续运行。我们用程序实现一下,代码如下:
等待线程WaitThread.java
通知线程NotifyThread.java
测试运行类Test.java
运行结果:
在控制台输出的运行结果可以看出,3秒后wait线程被notify线程的notify通知唤醒。
我们继续进行实验,如何使用wait()与notify()来实现前面size()值等于5的实验呢?代码如下:
类MyList.java
线程类WaitThreadA.java
线程类NotifyThreadA.java
运行测试类TestOne.java
运行结果:
在控制台输出的结果可以看出wait end 是最后输出,也就说明notify()方法执行后并不立即释放锁。
关键字synchronized可以将任何一个Object对象作为同步对象来看待,而Java为每个Object都实现了wait()和notify()方法,它们必须用在被synchronized同步的Object的临界区内。通过调用wait()方法可以使处于临界区内的线程进入等待状态,同时释放被同步对象的锁。而notify操作可以唤醒一个因调用了wait操作而处于阻塞状态中的线程,使其进入就绪状态。被重新唤醒的线程会试图重新获得临界区的控制全,也就是锁,并继续执行临界区内wait之后的代码。如果发出notify操作时没有处于阻塞状态中的线程,那么该命令会被忽略。
wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒。
notify()方法可以随及唤醒等待队列中等待同一共享资源的“一个”线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知“一个”线程。
notifyAll()方法可以使所有正在等待队列中等待同一共享资源的“全部”线程从等待状态退出,进入可运行状态。此时,优先级最高的那个线程最先执行,但也由可能是随机执行,因为这要取决于jvm虚拟机的实现。
根据Java中和Thread有关的API可以改变线程对象的状态,如下图:
详细解释一下:
1)新创建一个新的线程对象后,在调用它的start()方法,系统会为此线程分配cpu资源,使其处于Runnable(可执行)状态,这是一个准备运行的阶段。如果线程抢占到cpu资源,此线程处于Running(运行)状态。
2)Runnable状态和Running状态可相互切换,因为由可能线程运行一段时间后,有其他高优先级的线程抢占了cpu资源,这时线程就从Running状态变成Runnable状态。线程进入Runnable状态大体分为如下5种情况:
1.调用sleep()方法后经过的时间超过了指定的休眠时间。
2.线程调用的阻塞IO已经返回,阻塞方法执行完毕。
3.线程成功的获取了试图同步的监听器。
4.线程正在等待某个通知,其他线程发出了通知。
5.处于挂起状态的线程调用了resume恢复方法。
3)Blocked是阻塞的意思,例如遇到了一个IO操作,此时cpu处于空闲状态,可能会转而把cpu时间片分配给其他线程,这时也可以称为“暂停”状态。Bloaked状态结束后,进入Runnable状态,等待系统重新分配资源。出现阻塞的情况大体分为如下5种:
1.线程调用sleep方法,主动放弃占用的cpu资源。
2.线程调用了阻塞式IO方法,在该方法返回前,该线程被阻塞。
3.线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有。
4.线程等待某个通知。
5.程序调用了suspend方法将该线程挂起。此方法容易导致死锁,尽量避免使用该方法。
4)run()方法运行结束后进入销毁阶段,整个线程执行完毕。
每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列。就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程。一个线程被唤醒后,才会进入就绪队列,等待cpu的调度;反之,一个线程被wait后,就会进入阻塞队列,等待下一次被唤醒。
大家在学习过程中遇到过什么问题也欢迎在留言区盖楼讨论!
以上是关于多线程的wait/notify的使用的主要内容,如果未能解决你的问题,请参考以下文章
多线程之wait,notify,volatile,synchronized,sleep