多线程(五)~ wait/notify机制(等待/通知)
首先我们来看一张图,这张图描述了线程操作的几个步骤。
图已经描述的很清楚了,这里除了wait()之外,其他的前面都已经接触过了。
这一章我们主要来说一下和wait()相关的操作,其实和wait()相关的还有另外两个函数notity()和notifyAll()。
这三个函数都是Object类里的方法
wait():使调用此方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒
notify():随机唤醒等待队列中等待同一个共享资源的“一个”线程,并使该线程退出等待队列,进入可运行状态,也就是说notofy()通知唤醒一个线程。
notifyAll():使所有正在等待队列中等待同一个共享资源的“全部”线程从等待状态退出,进入可运行状态。
注意:notify()和notifyAll()后并不是直接就释放锁的,而是等notify()后的代码执行完毕后才释放锁。而且这三个方法都必须在synchronize代码块里执行,否则会报错。
每个对象都有两个队列,一个是就绪队列,一个是阻塞队列。就绪队列存储了将要获得锁的线程,阻塞队列存储了所有被阻塞的线程。一个线程被唤醒后,才会进入就绪队列,等待CPU的调度,反之,一个线程被wait()之后,线程就进入了阻塞队列,等待下一次被唤醒。
线程会释放锁的三种情况:
1.线程任务执行完毕,释放锁。
2.线程调用wait()方法,释放锁。
3.线程执行过程中发生异常,释放锁。
生产-消费者模式:
单生产者,单消费者demo:
①.生产者:
package com.multiThread.bean;
publicclass P {
privateObject lock;
public P(Object lock){
this.lock = lock;
}
publicvoidSetValue(){
try{
synchronized(lock){
if(!ValueObject.value.equals("")){
lock.wait();
}
String value =System.currentTimeMillis()+"_"+System.nanoTime();
System.out.println("set值为:"+ value);
ValueObject.value = value;
lock.notify();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
②.消费者
package com.multiThread.bean;
publicclass C {
privateObject lock;
public C(Object lock){
this.lock = lock;
}
publicvoid getValue(){
try{
synchronized(lock){
if(ValueObject.value.equals("")){
lock.wait();
}
System.out.println("get的值:"+ValueObject.value);
ValueObject.value ="";
lock.notify();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
③.生产者线程类
package com.multiThread.thread;
import com.multiThread.bean.P;
publicclassThreadPimplementsRunnable{
private P p;
publicThreadP(P p){
this.p = p;
}
@Override
publicvoid run(){
while(true){
p.SetValue();
}
}
}
④.消费者线程类
package com.multiThread.thread;
import com.multiThread.bean.C;
publicclassThreadCimplementsRunnable{
private C c;
publicThreadC(C c){
this.c = c;
}
@Override
publicvoid run(){
while(true){
c.getValue();
}
}
}
⑤.测试类
package com.multiThread.test.productionConsumption;
import com.multiThread.bean.C;
import com.multiThread.bean.P;
import com.multiThread.thread.ThreadC;
import com.multiThread.thread.ThreadP;
/**
* 等待、通知机制
*/
publicclassProduceCustomTest{
publicstaticvoid main(String[] args){
Object lock =newObject();
P p =new P(lock);
C c =new C(lock);
ThreadP tp =newThreadP(p);
ThreadC tc =newThreadC(c);
Thread t1 =newThread(tp);
Thread t2 =newThread(tc);
t1.start();
t2.start();
}
}
执行结果:
set值为:1466176983137_22743411842275
get的值:1466176983137_22743411842275
set值为:1466176983137_22743412731096
get的值:1466176983137_22743412731096
set值为:1466176983137_22743412952232
get的值:1466176983137_22743412952232
set值为:1466176983137_22743413140860
get的值:1466176983137_22743413140860
- .
- .
- .
可见生产者和消费者是交替执行的。
这里仅仅是单生产者和消费者。如果是多生产者和消费者会正常运行吗?
答案是否定的。因为notify()之后是随机唤醒一个线程,如果生产者唤醒的是生产者,那么就会一直处于wait(),造成死锁。
解决问题的方法:
将notify()方法换成notifyAll()