wait()和notify()
大致使用方式
在synchronized代码块中使用wait()方法可以使该线程等待并启用另外一个方法,当另外一个线程在同一个对象的另一块方法块中使用notify()方法便可以唤醒那个进入等待状态的线程。
深入理解
其实知道它们两个方法的使用方法后,笔者是有所困惑的,因为相关代码仅仅知道基本使用方法逻辑上解释不通,于是上网查找了一些资料,最终豁然开朗,由于笔者的能力时间有限这里的深入理解只是在代码中增加显示语句使语句使效果显示出来,其实最深入的理解应该去看源码,只能说下次一定把。
结论
当线程执行wait()方法时候,会立即释放当前的锁,然后让出CPU,进入等待状态,这里立即释放很重要,就是剩下的工作全不做了,先释放锁。
这里与notify()方法对比:
notify()的执行必须跳出了synchronized,才能够通知到其他线程,就是要释放了自己的锁,所以当线程遇到notify()方法时没有立马释放锁而是继续执行代码等到释放锁的时机出现,再释放锁,使等待线程苏醒继续实行wait()方法之后的代码。
接下来我们用一段经典生产者和消费者的代码来演示这两个特点。
演示
为了直观的显示我们在厨师这个线程的wait()方法后添加显示System.out.println(“233”);
在服务员这段线程的notify()方法后添加显示
System.out.println(“23333”);
通过观察这两个输出的时机更加形象的展现上一节的结论
// An highlighted block
public class Example {
public static void main(String[] args) {
//多线程通信 生产者与消费者问题
Food f = new Food();
new Cook(f).start();
new Waiter(f).start();
}
//厨师
static class Cook extends Thread{
private Food f;
public Cook(Food f) {
this.f = f;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if(i%2==0){
f.setNameAndTaste("老干妈小米粥","香辣味");
}else {
f.setNameAndTaste("煎饼果子","甜辣味");
}
}
}
}
//服务员
static class Waiter extends Thread{
private Food f;
public Waiter(Food f) {
this.f = f;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
f.get();
}
}
}
//食物
static class Food{
private String name;
private String taste;
//true表示可以生产
boolean flag = true;
public synchronized void setNameAndTaste(String name,String taste){
if(flag){
this.name = name;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.taste = taste;
flag = false;
this.notifyAll();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("233");
}
}
public synchronized void get(){
if(!flag){
System.out.println("服务员端走的菜的名称是:"+name+",味道是:"+taste);
flag = true;
this.notifyAll();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("23333");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
输出结果如下:
服务员端走的菜的名称是:老干妈小米粥,味道是:香辣味
23333
233
服务员端走的菜的名称是:煎饼果子,味道是:甜辣味
23333
233
服务员端走的菜的名称是:老干妈小米粥,味道是:香辣味
23333
233
......
由此可见在执行完wait()方法后其后面的输出System.out.println(“233”);并没有立马执行,而是锁被立即释放,下一个线程占用了空间,而当notify()方法方法执行时并没有立马释放锁而是继续执行System.out.println(“23333”);等遇见了wait()方法方法后才释放锁.得以执行System.out.println(“233”);,才造就了上述输出。