上节,我们谈到了生产者/消费者模型,这里,我不得不把我的一次实验结果粘贴出来,本来第一次运行的挺好的,可是第二次竟然出现了如下结果:
Producer:p produced:1
Consumer:c consumed:1
Consumer:c consumed:2
Producer:p produced: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
奇怪,怎么第三行是消费,第四行才是生产者,我开始是怀疑我手一哆嗦点错了,可是,在经过数次运行之后,仍然出现了消费在前,生产在后......
嘿嘿,其实这是假象,我们看到的并不是先消费再生产,其实确实是先生产再消费,只是控制台先打印出了消费语句再打印出了生产语句.为什么呢?这是因为生产者线程生产数据(put())之后未打印生产语句之前突然由于某种原因(如时间分片完毕)发生中断,导致没及时打印生产语句,这时,消费者夺得了cpu资源,取走数据并打印了消费语句,随后当cpu重新处理生产者线程时,回到刚才生产者线程的中断现场,执行完刚没执行的生产语句.这就造成了先消费后生产的假象.可以想象,这样的一个视觉性漏洞,是会给实际应用带来重大损失的.
那么,如何改变这一弊端呢?第一种思路就是我们可以将打印语句写在同步方法中,即把生产语句写在put()中,消费语句写在get()中,这样,如果线程进入到了put()中,即使这时突然中断,生产者线程也不会交出对象锁,消费者线程也不会执行get()了,更不会在生产语句之前打印get()中的消费语句了.第二种思路就是我们不让生产方法(put())和消费方法(get())单独同步,而是让生产方法和生产语句一起和消费方法和消费语句一起同步,互相排斥.
上述方法在解决某些实际问题时需要三思后行,站在理解思想挖掘大脑潜力的基础上选取最佳方法,需要我们灵活运用.
这里我采取第二种方法.
我们先定义要处理的资源(Box):
public class Box {
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 class Producer extends Thread {
private Box box;// 要处理的资源
private String name;// 生产者名称
// 构造器
public Producer(Box box, String name) {
this.box = box;
this.name = name;
}
public void run() {
synchronized (box) {
for (int i = 1; i < 6; i++) {
box.put(i);// 写入数据i(即给box中的value设定初值)
System.out.println("Producer:" + name + " " + "produced:" + i);// 打印
try {
sleep((int) (Math.random() * 100));// 强制睡眠,用以等待消费者取走数据
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
线程--消费者:
public class Consumer extends Thread {
private Box box;// 要处理的资源
private String name;// 消费者名称
// 构造器
public Consumer(Box box, String name) {
this.box = box;
this.name = name;
}
public void run() {
synchronized (box) {
int value = 0;
for (int i = 1; i < 6; i++) {
value = box.get();// 取走数据(即获取box的value值)
System.out.println("Consumer:" + name + " " + "consumed:"
+ value);
try {
sleep((int) (Math.random() * 100));// 强制睡眠,用以等待生产者生产数据
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
测试类:
package produceConsumer;
public class ProducerConsumerTest {
public static void main(String[] args) {
Box box = new Box();
new Producer(box, "p").start();
new Consumer(box, "c").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的方式去实现java多线程入门一中的生产者/消费者模型.
下接:java多线程入门三
http://172672421-qq-com.iteye.com/admin/blogs/1129791
分享到:
相关推荐
java多线程入门,资料中讲述了从线程的入门到精通
java多线程入门
对于线程的入门 ,对于一个java程序猿 很重要
1. Java多线程学习(一)Java多线程入门 2. Java多线程学习(二)synchronized关键字(1) 3. Java多线程学习(二)synchronized关键字(2) 4. Java多线程学习(三)volatile关键字 5. Java多线程学习(四)...
java多线程小程序实例 java多线程小程序实例
内含 chapter02-chapter18 共 17 个实例性源码项目,内容循序渐进,由入门到精通。尤其适合于没有 Java 线程开发经验的朋友。自己动手敲出本资源解压缩后的 ...相信你理解了此源码之后,即可步入 Java 多线程开发。
必知必会的多线程入门基础知识
运用JAVA语言编辑多线程程序,初学入门教程,PPT格式,直观
随着现代处理器的生产工艺从提升...《Java多线程编程实战指南(核心篇)》适合有一定Java语言基础的读者作为入门多线程编程之用,也适合有一定多线程编程经验的读者作为重新梳理知识结构以提升认知层次和参考之用。
黑马+传智 Java入门到精通视频教程+课件+代码,30套Java开发项目代码,Java多线程与并发库高级应用视频教程,及电子书,面试题,开发工具等
一个java多线程的入门程序,运行开发利用j2sdk1.4.1_01,相信它会对你有一定帮助,能帮你多少那就要看你了
【完整课程列表】 ... 完整版精品java课件 ...完整版精品java课件 Java基础入门教程 Java程序设计 第13章 多线程(共24页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第14章 socket网络编程(共24页).ppt
Java线程入门大全 详细介绍了java的多线程技术
日本经典多线程入门书,原版长销11年! 1.图文并茂 通俗易懂 日本资-深技术作家、《程序员的数学》作者结城浩执笔,264张图表(UML类图、时序图、Timethreads图等)穿插文中,通过类比手法和浅显的语言,逐一讲解与...
适合初级程序员入门学习java的多线程机制
在使用java线程的时候,特别是初学者总会有几点很常见的误区 对JAVA入门编程人员的一点建议
这个资料从多线程的基本概念讲起,一直到能够熟练使用多线程,看完这个后能够直接进行多线程的程序开发,资料比较全面。
此教程适用于拥有丰富 Java 语言应用知识,但又没有多少多线程或并发性经验的 Java 程序员。