( 1 )等待唤醒机制就是用于解决线程间通信的问题的,使用到的3个方法的含义如下:
wait:告诉当前线程放弃执行权,并放弃监视器(锁)并进入阻塞状态,直到其他线程持有获得执行权,并持有了相同的监视器(锁)并调用notify为止。
notify:唤醒持有同一个监视器(锁)中调用wait的第一个线程,例如,餐馆有空位置后,等候就餐最久的顾客最先入座。注意:被唤醒的线程是进入了可运行状态。等待cpu执行权。
notifyAll:唤醒持有同一监视器中调用wait的所有的线程。
( 2 )调用wait和notify方法需要注意的细节:
wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。
( 3 ) waite和sleep方法的区别
1.相同之处:
线程调用wait()或者是sleep()方法都会进入临时阻塞状态,会释放cpu的执行权。调用时都需要处理 InterruptedException异常。
2.不同之处:
wait(): 释放资源,释放锁。是Object的方法。
sleep():释放资源,不释放锁。是Thread的静态方法
下面通过例子来说明.
/**
* 要实现的效果就是,有一个水池,水池的容量为50L,一个放水线程,负责放水,每200毫秒放出1L水,当水放完后,通知注水线程工作,同时放水线程停止工作;
* 注水线程每200毫秒注水1L,水注满时,再通知放水线程继续工作,同时注水线程停止工作.
*
* @author mChenys
*
*/
public class _Main5 {
public static void main(String[] args) {
Pool pool = new Pool();
WaterIn in = new WaterIn(pool, "注水线程");
WaterOut out = new WaterOut(pool, "放水线程");
in.start();
out.start();
}
}
/**
* 水池,容量为50L
*
* @author mChenys
*
*/
class Pool {
public int MAX_VLAUE = 50;
public int curr_value = 0;
}
/**
* 注水线程
*
* @author mChenys
*
*/
class WaterIn extends Thread {
private Pool pool;
public WaterIn(Pool pool, String name) {
super(name);
this.pool = pool;
}
@Override
public void run() {
while (true) {
synchronized (pool) {
try {
if (pool.curr_value < pool.MAX_VLAUE) {
// 加水
Thread.sleep(200);
pool.curr_value += 1;
System.out.println(this.getName() + "正在加水,加入 "
+ pool.curr_value + " L水");
} else if (pool.curr_value == pool.MAX_VLAUE) {
System.out.println(this.getName()
+ "水已加满!!,可以放水了......");
pool.notify();// 唤醒放水线程
pool.wait();// 当前线程等待,释放锁对象
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 放水线程
*
* @author mChenys
*
*/
class WaterOut extends Thread {
private Pool pool;
public WaterOut(Pool pool, String name) {
super(name);
this.pool = pool;
}
@Override
public void run() {
while (true) {
synchronized (pool) {
try {
if (pool.curr_value > 0) {
// 放水
Thread.sleep(200);
pool.curr_value -= 1;
System.out.println(this.getName() + "开始放水,放出 "
+ (pool.MAX_VLAUE - pool.curr_value) + " L水");
} else if (pool.curr_value == 0) {
System.out.println(this.getName() + "水已放完,可以加水了.....");
pool.notify();// 唤醒注水线程
pool.wait();// 当前线程等待,释放锁对象
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
注水线程正在加水,加入 20 L水
注水线程正在加水,加入 40 L水
注水线程正在加水,加入 60 L水
注水线程正在加水,加入 80 L水
注水线程正在加水,加入 100 L水
注水线程正在加水,加入 120 L水
注水线程正在加水,加入 140 L水
注水线程正在加水,加入 160 L水
注水线程正在加水,加入 180 L水
注水线程正在加水,加入 200 L水
注水线程正在加水,加入 220 L水
注水线程正在加水,加入 240 L水
注水线程正在加水,加入 260 L水
注水线程正在加水,加入 280 L水
注水线程正在加水,加入 300 L水
注水线程正在加水,加入 320 L水
注水线程正在加水,加入 340 L水
注水线程正在加水,加入 360 L水
注水线程正在加水,加入 380 L水
注水线程正在加水,加入 400 L水
注水线程正在加水,加入 420 L水
注水线程正在加水,加入 440 L水
注水线程正在加水,加入 460 L水
注水线程正在加水,加入 480 L水
注水线程正在加水,加入 500 L水
注水线程水已加满!!,可以放水了......
放水线程开始放水,放出 20 L水
放水线程开始放水,放出 40 L水
放水线程开始放水,放出 60 L水
放水线程开始放水,放出 80 L水
放水线程开始放水,放出 100 L水
放水线程开始放水,放出 120 L水
放水线程开始放水,放出 140 L水
放水线程开始放水,放出 160 L水
放水线程开始放水,放出 180 L水
放水线程开始放水,放出 200 L水
放水线程开始放水,放出 220 L水
放水线程开始放水,放出 240 L水
放水线程开始放水,放出 260 L水
放水线程开始放水,放出 280 L水
放水线程开始放水,放出 300 L水
放水线程开始放水,放出 320 L水
放水线程开始放水,放出 340 L水
放水线程开始放水,放出 360 L水
放水线程开始放水,放出 380 L水
放水线程开始放水,放出 400 L水
放水线程开始放水,放出 420 L水
放水线程开始放水,放出 440 L水
放水线程开始放水,放出 460 L水
放水线程开始放水,放出 480 L水
放水线程开始放水,放出 500 L水
放水线程水已放完,可以加水了.....
注水线程正在加水,加入 20 L水
注水线程正在加水,加入 40 L水
注水线程正在加水,加入 60 L水
注水线程正在加水,加入 80 L水
注水线程正在加水,加入 100 L水
注水线程正在加水,加入 120 L水
注水线程正在加水,加入 140 L水
注水线程正在加水,加入 160 L水
注水线程正在加水,加入 180 L水
注水线程正在加水,加入 200 L水
注水线程正在加水,加入 220 L水
注水线程正在加水,加入 240 L水
注水线程正在加水,加入 260 L水
注水线程正在加水,加入 280 L水
注水线程正在加水,加入 300 L水
注水线程正在加水,加入 320 L水
注水线程正在加水,加入 340 L水
注水线程正在加水,加入 360 L水
注水线程正在加水,加入 380 L水
注水线程正在加水,加入 400 L水
注水线程正在加水,加入 420 L水
注水线程正在加水,加入 440 L水
注水线程正在加水,加入 460 L水
注水线程正在加水,加入 480 L水
注水线程正在加水,加入 500 L水
注水线程水已加满!!,可以放水了......
放水线程开始放水,放出 20 L水
放水线程开始放水,放出 40 L水
放水线程开始放水,放出 60 L水
放水线程开始放水,放出 80 L水
放水线程开始放水,放出 100 L水
放水线程开始放水,放出 120 L水
放水线程开始放水,放出 140 L水
放水线程开始放水,放出 160 L水
放水线程开始放水,放出 180 L水
放水线程开始放水,放出 200 L水