**
线程间通讯
**
一般来说,在一个应用程序中,一个线程往往不是孤立存在的,常常需要与其他线程通信,以执行特定的任务。
Java通过等待通知机制实现了进程之间的通讯,有两点注意事项:
1.必须保证等待和唤醒线程只能有一个在执行(我们可以使用同步代码块来保证这一点)
2. 锁对象必须保持唯一
我们来看一下代码的实现:具体的流程为:
创建一个顾客线程:告知老板线程需要什么,然后调用wait方法,放弃cpu的执行。
创建一个老板线程:准备好后调用notify方法唤醒顾客线程。
public static void main(String[] args) {
Object obj=new Object();//创建锁对象
//创建顾客线程
new Thread() {
@Override
public void run() {
synchronized(obj) {
System.out.println("告诉老板需求");
try {
obj.wait();//要用锁对象来调用wait方法
} catch (InterruptedException e) {
System.out.println("调用wait异常");
e.printStackTrace();
}
System.out.println("拿到需求");
}
}
}.start();
//创建老板线程
new Thread() {
@Override
public void run() {
synchronized(obj) {
try {
Thread.sleep(1000);//花一秒的时间准备需求
} catch (InterruptedException e) {
System.out.println("准备需求时异常");
e.printStackTrace();
}
System.out.println("告知顾客需求准备完毕");
obj.notify();
//要用锁对象来调用notify方法来唤醒等待的单个线程(选取等待时间最久的线程)(notifyAll方法可以唤醒所有的waiting线程),会继续执行上面wait后面的代码
}
}
}.start();
}
结果
告诉老板需求
告知顾客需求准备完毕
拿到需求
只看代码其实非常好理解,顾客线程与老板线程通过wait方法与notify方法实现了线程之间的通讯。
下面我们来看一个复杂一点的案例。我们创建三个类,Consumer(顾客类),Cook(厨师类)与Dish(菜)。流程大概为:
顾客来到餐厅点餐,然后等待上菜,厨师收到信息后开始做菜,菜做好了上菜,顾客把菜吃完。
Dish类
public class Dish {
boolean flag=false;
//flag代表有没有菜,我们默认没有
}
Cook类
public class Cook implements Runnable {
private Dish dish;
public Cook(Dish dish)
{
this.dish=dish;
}
@Override
public void run() {
synchronized(dish) {
if(dish.flag==true) {//如果有菜
try {
dish.wait();//Cook进入等待
} catch (InterruptedException e) {
System.out.println("Cook的等待出错");
e.printStackTrace();
}
}
System.out.println("正在做菜");
try {
Thread.sleep(3000);//做菜所用的时间(3秒)
} catch (InterruptedException e) {
System.out.println("Cook做菜出错");
e.printStackTrace();
}
System.out.println("菜已经做好了");
dish.flag=true;
dish.notify();//做好菜后唤醒consumer
}//synchronized代码块
}
}
Consumer类
public class Consumer implements Runnable {
private Dish dish;
public Consumer(Dish dish)
{
this.dish=dish;
}
@Override
public void run() {
synchronized(dish) {
System.out.println("点菜");
try {
System.out.println("等待上菜");
dish.wait();
} catch (InterruptedException e) {
System.out.println("Consumer等待出错");
e.printStackTrace();
}
dish.notify();
if(dish.flag==true) {//如果有菜
System.out.println("正在吃菜");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("饭菜出错");
e.printStackTrace();
}
System.out.println("吃完");
dish.flag=false;
}
}//synchronized
}
}
main方法运行
public static void main(String[] args) {
Dish dish=new Dish();
Consumer consumer=new Consumer(dish);
Cook cook=new Cook(dish);//保证同步代码块的dish是同一个
Thread t1=new Thread(consumer);
Thread t2=new Thread(cook);
t1.start();
t2.start();
//没有加入死循环,所以wait的线程就不可以在被开启,导致一次循环可能无法全部打印六条语句
}
结果
点菜
等待上菜
正在做菜
菜已经做好了
正在吃菜
吃完
这次的更新比较短,只是把线程留下的一点知识做一个结尾,下次更新File类的有关知识。