1、线程通信的必要性
多线程不仅共享资源,而且相互牵制向前运行。
2、线程通信的方法(都是在Object中定义)
3个方法:
1) wait() 可运行转入阻塞状态,放锁
2) notify() 阻塞转入可运行状态,获得锁
3) notifyAll() 所有调用wait方法而被挂起的线程重新启动,有个条件:wait与notifyAll必须是属于同一个对象
必须在同步方法或同步代码块中使用
3、共享资源类(仓库)
注:共享资源(产品),牵制信息(产品有无)
package com.ljb.app.communication;
/**
* 共享资源类
* @author LJB
* @version 2015年3月11日
*/
public class ShareData {
// 产品
private char c;
// 牵制信息(产品有无,开始时仓库中没有产品)
private boolean isProduced = false;
/*
* 放产品(生产产品)
*/
public synchronized void putShareChar (char c) {
// 如果消费者还没有消费或者仓库中有产品,则生产者等待
if (isProduced) {
System.out.println("消费者还未消费,因此生产者停止生产。");
try {
wait();// 生产者等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 仓库中放入生产的产品
this.c = c;
// 改变信号量(有产品)
isProduced = true;
// 通知消费者消费
notify();
System.out.println("生产者生产了产品" + c + ",通知消费者消费...");
}
/*
* 取产品(消费产品)
*/
public synchronized char getShareChar () {
// 如果生产者还未生产或者仓库中没有产品,则消费者等待
if (!isProduced) {
System.out.println("生产者还未生产,因此消费者停止消费。");
try {
wait();// 消费者等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 改变信号量(没有产品或者消费了该产品)
isProduced = false;
// 通知生产者生产
notify();
System.out.println("消费者消费了产品" + c + ",通知生产者生产...");
return this.c;
}
}
4、生产者线程
package com.ljb.app.communication;
/**
* 生产者线程,每隔一段时间生产一个产品
* @author LJB
* @version 2015年3月11日
*/
public class Producer extends Thread{
// 共享资源对象
private ShareData s;
// 有参构造方法
public Producer (ShareData s) {
this.s = s;
}
public void run () {
for (char ch = 'A' ; ch <= 'D' ; ch++) {
try {
Thread.sleep((int)(Math.random()*3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
s.putShareChar(ch);// 将产品放入仓库
}
}
}
5、消费者线程
package com.ljb.app.communication;
/**
* 消费者线程
* @author LJB
* @version 2015年3月11日
*/
public class Consumer extends Thread{
// 共享资源
private ShareData s;
// 构造方法
public Consumer (ShareData s) {
this.s = s;
}
public void run () {
char ch;
do {
try {
Thread.sleep((int)(Math.random()*3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
ch = s.getShareChar();// 从仓库中取出产品
} while (ch != 'D');
}
}
6、测试类
package com.ljb.app.communication;
/**
* 测试类
* @author LJB
* @version 2015年3月11日
*/
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
ShareData s = new ShareData();
Thread consumer = new Consumer(s);
consumer.start();
Thread producer = new Producer(s);
producer.start();
}
}
运行结果:
生产者还未生产,因此消费者停止消费。
生产者生产了产品A,通知消费者消费...
消费者消费了产品A,通知生产者生产...
生产者生产了产品B,通知消费者消费...
消费者消费了产品B,通知生产者生产...
生产者生产了产品C,通知消费者消费...
消费者消费了产品C,通知生产者生产...
生产者生产了产品D,通知消费者消费...
消费者消费了产品D,通知生产者生产...