Java并发与多线程(2) 生产者与消费者
2016-04-01 02:09
337 查看
老师的源码
今天看了一下老师给的代码,跑了一下发现会有bug:即生产者的产品输出会在消费者的购买的输入之后(部分),尝试了几种改的方法
我最终的改法
import java.lang.Thread;
class Producer extends Thread {
private Tray tray;
private int id;
public Producer ( Tray t, int id){
tray = t;
this.id = id;
//new Thread(this,"Producer");
}
public void run () {
for( int i = 0; i < 10; i++) {
for( int j = 0; j < 10; j++) {
synchronized(tray){
tray.put(i, j);
System.out.println("Producer #" + id + "put:(" + i + "," + j + ").");
}
try{
sleep(100); // 这个sleep可以去掉的,不影响
} catch( InterruptedException e ) {
System.out.println("Producer Interrupted");
}
}
// System.out.println("hhhh");
}
}
}
class Consumer extends Thread {
private Tray tray;
private int id;
public Consumer ( Tray t, int id ) {
tray = t;
this.id = id;
//new Thread(this,"Consumer");
}
public void run () {
int value = 0;
for( int i = 0; i < 100; i++) {
synchronized (tray) {
value = tray.get();
System.out.println("Consumer #" + id + "got: " + value);
// try{
// sleep(10);
// } catch ( InterruptedException e ) {
// System.out.println("Consumer Interrupted");
}
}
}
}
class Tray {
private int x;
private int y;
private boolean available = false;
public synchronized int get() {
while ( available == false ) {
try{
wait();
} catch( InterruptedException e ) {
System.out.println("Tray Wrong");
}
}
//System.out.println("Consumer #" + "got: " + (x+y));
available = false;
super.notify();
return x + y;
//notifyAll();
}
public synchronized void put( int a, int b) {
while ( available == true ) {
try{
wait();
} catch( InterruptedException e) {
System.out.println("Tray Wrong 2");
}
}
//System.out.println("Producer #" + "put:(" + a + "," + b + ").");
available = true;
x = a;
y = b;
super.notify();
//notifyAll();
}
}
public class Test {
public static void main ( String [] args ) {
Tray t = new Tray();
Producer p1 = new Producer(t,1);
Consumer c1 = new Consumer(t,1);
p1.start();
c1.start();
try{
Thread.sleep(10000);
} catch ( InterruptedException e ) {
System.out.println("Thread Interrupted");
}
System.out.println("End");
}
}
做的改动有
1.改变了消费者类的run()方法的循环次数,改成了100次,和生产者的总循环次数保持一致
2.把run()方法里面的进行put()或者get()和输出用synchronized块括起来
分析:
出现bug的原因不是先消费后生产,而是因为print的时候会有延迟,这个延迟多久也是不好控制的,然后这个时候消费者已经可以开始消费了,就导致了消费者的输出先于生产者,所以写同步块的效果就是把输出的时候限定在切换到另一个进程之前。这样子的话,把put和get方法的前面的synchronized关键字去掉也是可以的。
public class Producer extends Thread { private Tray tray; private int id; public Producer(Tray t, int id) { tray = t; this.id = id; } public void run() { for (int i = 0; i < 10; i++) for(int j =0; j < 10; j++ ) { tray.put(i, j); System.out.println("Producer #" + this.id + " put: ("+i +","+j + ")."); try { sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } }; } } public class Consumer extends Thread { private Tray tray; private int id; public Consumer(Tray t, int id) { tray = t; this.id = id; } public void run() { int value = 0; for (int i = 0; i < 10; i++) { value = tray.get(); System.out.println("Consumer #" + this.id + " got: " + value); } } } public class Tray { private int x,y; private boolean available = false; public synchronized int get() { while (available == false) { try { wait(); } catch (InterruptedException e) { } } available = false; // 此时available为真,确保所有其他消费者等待 notifyAll(); return x+y; } public synchronized void put(int a, int b) { while (available == true) { try { wait(); } catch (InterruptedException e) { } } available = true; // 唤醒等待队列中的其他消费者或生产者 x= a; y = b; notifyAll(); } } public class ProducerConsumerTest { public static void main(String[] args) { Tray t = new Tray(); Producer p1 = new Producer(t, 1); Consumer c1 = new Consumer(t, 1); p1.start(); c1.start(); } }
今天看了一下老师给的代码,跑了一下发现会有bug:即生产者的产品输出会在消费者的购买的输入之后(部分),尝试了几种改的方法
我最终的改法
import java.lang.Thread;
class Producer extends Thread {
private Tray tray;
private int id;
public Producer ( Tray t, int id){
tray = t;
this.id = id;
//new Thread(this,"Producer");
}
public void run () {
for( int i = 0; i < 10; i++) {
for( int j = 0; j < 10; j++) {
synchronized(tray){
tray.put(i, j);
System.out.println("Producer #" + id + "put:(" + i + "," + j + ").");
}
try{
sleep(100); // 这个sleep可以去掉的,不影响
} catch( InterruptedException e ) {
System.out.println("Producer Interrupted");
}
}
// System.out.println("hhhh");
}
}
}
class Consumer extends Thread {
private Tray tray;
private int id;
public Consumer ( Tray t, int id ) {
tray = t;
this.id = id;
//new Thread(this,"Consumer");
}
public void run () {
int value = 0;
for( int i = 0; i < 100; i++) {
synchronized (tray) {
value = tray.get();
System.out.println("Consumer #" + id + "got: " + value);
// try{
// sleep(10);
// } catch ( InterruptedException e ) {
// System.out.println("Consumer Interrupted");
}
}
}
}
class Tray {
private int x;
private int y;
private boolean available = false;
public synchronized int get() {
while ( available == false ) {
try{
wait();
} catch( InterruptedException e ) {
System.out.println("Tray Wrong");
}
}
//System.out.println("Consumer #" + "got: " + (x+y));
available = false;
super.notify();
return x + y;
//notifyAll();
}
public synchronized void put( int a, int b) {
while ( available == true ) {
try{
wait();
} catch( InterruptedException e) {
System.out.println("Tray Wrong 2");
}
}
//System.out.println("Producer #" + "put:(" + a + "," + b + ").");
available = true;
x = a;
y = b;
super.notify();
//notifyAll();
}
}
public class Test {
public static void main ( String [] args ) {
Tray t = new Tray();
Producer p1 = new Producer(t,1);
Consumer c1 = new Consumer(t,1);
p1.start();
c1.start();
try{
Thread.sleep(10000);
} catch ( InterruptedException e ) {
System.out.println("Thread Interrupted");
}
System.out.println("End");
}
}
做的改动有
1.改变了消费者类的run()方法的循环次数,改成了100次,和生产者的总循环次数保持一致
2.把run()方法里面的进行put()或者get()和输出用synchronized块括起来
分析:
出现bug的原因不是先消费后生产,而是因为print的时候会有延迟,这个延迟多久也是不好控制的,然后这个时候消费者已经可以开始消费了,就导致了消费者的输出先于生产者,所以写同步块的效果就是把输出的时候限定在切换到另一个进程之前。这样子的话,把put和get方法的前面的synchronized关键字去掉也是可以的。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python3写爬虫(四)多线程实现数据爬取
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序