上节我们讲到如何避免线程中断带来的视觉漏洞,实际上,不足以说明问题,在通过不断的学习和深入思考里,往往能挖掘出更简单更直观的算法和技巧.温故而知新---这话一点都不假.
上两节,我们构造的线程都是通过继承Thread类,实际上,有些时候,我们不能够这么做:假如一个已经继承了另外一个父类的类,你还能让它继承Thread吗?很明显不能.Runnale能为你解决这一难题.甚至可以说,Runnable不仅为你解决java类单继承的缺陷,还能为你解决许多难题,它能使代码更简洁,使思路更清晰.下面,我将前面的生产者/消费者模型用实现Runnable接口的形式来完成.
我们先定义要处理的资源(Box):
public class Box implements Runnable {
private int value;// 要进行读写的值
private boolean available = false;// 开关变量,true即表示value已生产,false即表示value已消费
public int get() {
while (available == false) {// Box无数据
try {
wait();// 交出对象锁,等待生产者写入数据
} catch (InterruptedException e) {
e.printStackTrace();
}
}
available = false;// 开关变量取反,示意消费者可以取走数据
notifyAll();// 唤醒线程池中所有阻塞线程
return value;
}
public void put(int value) {
while (available == true) {// Box有数据
try {
wait();// 交出对象锁,等待消费者取走数据
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.value = value;
available = true;// 开关变量取反,示意生产者可以生产数据
notifyAll();// 唤醒线程池中所有阻塞线程
}
public void run() {
//循环,两个线程协调完成任务
while (this.value <= 5) {
//Box无数据时
if (!available) {
synchronized (this) {
if (this.value < 5) {
for (int i = 1; i < 6; i++) {
this.put(i);
System.out.println("Producer:" + "p" + " "
+ "produced:" + i);
}
}
}
//当value值为5时,跳出,不再生产数据
if(this.value==5){
return;
}
}
//Box有数据时
if (available) {
synchronized (this) {
for (int i = 1; i < 6; i++) {
System.out.println("Consumer:" + "c" + " "
+ "consumed:" + this.get());
}
}
}
}
}
}
测试类:
public class ProducerConsumerTest {
public static void main(String[] args) {
Box box=new Box();//创建要处理的资源
new Thread(box).start();//构建一个生产者线程
new Thread(box).start();//构建一个消费者线程
}
}
运行结果:
Producer:p produced:1
Consumer:c consumed:1
Producer:p produced:2
Consumer:c consumed:2
Producer:p produced:3
Consumer:c consumed:3
Producer:p produced:4
Consumer:c consumed:4
Producer:p produced:5
Consumer:c consumed:5
很明显,我们省去了生产者类和消费者类,这也体现了,对于处理同一资源对象,Runnable相对于Thread的优势.欢迎提出改正意见,达到交流共同学习的目的.
下接:java多线程入门四
http://172672421-qq-com.iteye.com/admin/blogs/1128975