Java日志九「线程之间的通讯」

**

线程间通讯

**
一般来说,在一个应用程序中,一个线程往往不是孤立存在的,常常需要与其他线程通信,以执行特定的任务。

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类的有关知识。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值