Java并发与多线程(2) 生产者与消费者

老师的源码
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关键字去掉也是可以的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值