生产者与消费者怎么实现

一、synchronized正确写法示例
public class ProducerConsumer {
	// 仓库大小
	private static int num = 100;
	// 仓库货源数
	private static int count = 0;
	
	private static Object object = new Object(); 

	public static void main(String[] args) {
		// 实现Runable接口的生产者
		Producer producer = new Producer();
		// 实现Runable接口的消费者
		Consumer consumer = new Consumer();
		// 直接执行producer.run(),相当于执行普通的方法
		// 而使用Thread.start()才会具有线程的特性,所以实现Runable的类必须再用new Thread()
		Thread producerThread = new Thread(producer, "生产者");
		Thread consumerThread = new Thread(consumer, "消费者");
		// 使用start()的方法才具有线程的特性,执行run方法就会顺序执行
		// producerThread.run();
		producerThread.start();
		consumerThread.start();
	}
	
	/**
	 * @author YKQ
	 * 生产者
	 */
	static class Producer implements Runnable{
		/**
		 * 生产
		 */
		public  void produce() {
			// 两个类都使用object来加锁,则object锁了,会锁住持有object权限的线程
			// object.wait()会使得当前持有object的类进入阻塞状态
			// object.notify()会唤醒除了以object为锁的其他类
			// wait()只会使当前类阻塞
			// notify()只会唤醒当前类,因为,他相当于调用从父类Object继承过来的notify()方法
			synchronized(object) {
				for(int i=1;i<=1000;) {
					if(count<num) {
						count++;
						System.out.println("生产第"+i+"件商品!仓库还剩"+count+"商品!");							
						i++;
						object.notify();					
					} else {
						try {
							object.wait(1);
							object.notify();
						} catch (InterruptedException e) {
						}
					}
				}
			}
		}

		public void run() {
			produce();
		}
	}

	/**
	 * @author YKQ
	 * 消费者
	 */
	static class Consumer implements Runnable{
		private int sum = 0;
		/**
		 * 消费
		 */
		public void consume(){
			synchronized (object) {
				while(sum<=1000) {
					if(count>0) {
						sum++;
						count--;
						System.out.println("消费第"+sum+"商品!仓库还剩"+count+"商品!");
						object.notify();
					} else {
						try {
							object.wait(1);
							object.notify();
						} catch (InterruptedException e) 
						{
						}
					}
				}
			}
		}
		public void run() {
			consume();
		}
	}
}

二、synchronized错误实例
示例一

此时调用的notify方法是this.notify().当前this是Producer,因此不会唤醒Consumer.

synchronized(object) {
		for(int i=1;i<=1000;) {
			if(count<num) {
				count++;
				System.out.println("生产第"+i+"件商品!仓库还剩"+count+"商品!");							
				i++;
				// notify()相当于this.notify();然而synchronized的()不是this,是object
				// synchronized块{}中的wait和notify以及notifyAll方法必须是()中的对象的方法。
				// 比如Integer a = 1; synchronized(a){a.wait();a.notify(); } 
				// 或者synchronized(this){this.wait();this.notify()}
				// 不然会报IllegalMonitorStateException
				notify();					
			} else {
				try {
					wait();
					notify();
				} catch (InterruptedException e) {
				}
			}
		}
	}
示例二

Producer持有的锁是producer的this。Consumer持有的锁是Consumer的this。两者是不同对象,不会形成排队阻塞。

// 这样不会报Exception,但是生产者和消费者没有同步
// 虽然生产者和消费者synchronized()都是使用的this,但是两个this表示不同的含义
// Producer中的this表示的是Producer的对象
// Consumer中的this表示的是Consumer的对象
// 两个synchronized()想要同步必须是同一个锁
synchronized(this) {
	for(int i=1;i<=1000;) {
		if(count<num) {
			count++;
			System.out.println("生产第"+i+"件商品!仓库还剩"+count+"商品!");							
			i++;
			notify();					
		} else {
			try {
				wait();
				notify();
			} catch (InterruptedException e) {
			}
		}
	}
}
示例三
public class ProducerConsumer {
	// 仓库大小
	private static int num = 100;
	// 仓库货源数
	private static Integer count = 0;

	public static void main(String[] args) {
		// 实现Runable接口的生产者
		Producer producer = new Producer();
		// 实现Runable接口的消费者
		Consumer consumer = new Consumer();
		// 直接执行producer.run(),相当于执行普通的方法
		// 而使用Thread.start()才会具有线程的特性,所以实现Runable的类必须再用new Thread()
		Thread producerThread = new Thread(producer, "生产者");
		Thread consumerThread = new Thread(consumer, "消费者");
		// 使用start()的方法才具有线程的特性,执行run方法就会顺序执行
		// producerThread.run();
		producerThread.start();
		consumerThread.start();
	}
	
	/**
	 * @author YKQ
	 * 生产者
	 */
	static class Producer implements Runnable{
		/**
		 * 生产
		 */
		public  void produce() {
			// 这个地方既规避了示例一也规避了示例二的问题,为什么还是报了Excetion
			// 这是因为Integer count = 0; 这个地方使用到了封箱,将一个int封箱成Integer
			// 然后synchronized(count),但是在{}内部对该对象count进行开箱后+1,再封箱
			// 再封箱的过程导致count的对象已经改变,所以synchronized(count)中的count
			// 和count.notify()的count,严格上说不是一个对象。
			synchronized(count) {
				for(int i=1;i<=1000;) {
					if(count<num) {
						count++;
						System.out.println("生产第"+i+"件商品!仓库还剩"+count+"商品!");							
						i++;
						count.notify();					
					} else {
						try {
							count.wait();
							count.notify();
						} catch (InterruptedException e) {
						}
					}
				}
			}
		}

		public void run() {
			produce();
		}
	}

	/**
	 * @author YKQ
	 * 消费者
	 */
	static class Consumer implements Runnable{
		private int sum = 0;
		/**
		 * 消费
		 */
		public void consume(){
			synchronized (count) {
				while(sum<=1000) {
					if(count>0) {
						sum++;
						count--;
						System.out.println("消费第"+sum+"商品!仓库还剩"+count+"商品!");
						count.notify();
					} else {
						try {
							count.wait();
							count.notify();
						} catch (InterruptedException e) 
						{
						}
					}
				}
			}
		}
		public void run() {
			consume();
		}
	}
}
解析示例三的情况
public class HashTest {
	// 根据对象的hash值,来判断该对象是否发生改变
	// 下面的例子可以很好的说明,Integer在再装箱的过程中变成了另一个对象
	// 同时也举例说明了String在拼接时会变成另一个对象。
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Student student = new Student();
		System.out.println(student.hashCode());
		student.id = "123456";
		System.out.println(student.hashCode());
		student.name = "张三";
		System.out.println(student.hashCode());
		
		Integer a = 1;
		System.out.println(a.hashCode());
		a++;
		System.out.println(a.hashCode());
		
		String s = "123";
		System.out.println(s.hashCode());
		s += "456";
		System.out.println(s.hashCode());
	}
	
	static class Student{
		public String id;
		public String name;
	}
}
三、Lock与Condition正确写法示例
public class LockConditionTest {
    // 总产量
    private static int sum = 1000;
    // 仓库大小
    private static int capacity = 100;
    // 当前生产数量
    private static volatile int produceNum = 0;
    // 当前消费数量
    private static volatile int consumeNum = 0;
    // 当前仓库数量
    private static volatile int currNum = 0;

    // 创建lock锁,构造两个条件
    private static Lock lock = new ReentrantLock();
    private static Condition condition1 = lock.newCondition();
    private static Condition condition2 = lock.newCondition();

    public static void main(String[] args) {
        // 构造四个线程
        Producer producer1 = new Producer();
        Consumer consumer1 = new Consumer();
        FutureTask<Integer> producerTask1 = new FutureTask<>(producer1);
        FutureTask<Integer> consumerTask1 = new FutureTask<>(consumer1);
        Thread producerThread1 = new Thread(producerTask1);
        Thread consumerThread1 = new Thread(consumerTask1);

        // 启动线程
        producerThread1.start();
        consumerThread1.start();
    }

    public static class Producer implements Callable<Integer> {

        public Producer() {
        }

        @Override
        public Integer call() {
            while (produceNum < sum) {
                boolean hasLock = lock.tryLock();
                if (hasLock) {
                    try {
                        if (currNum < capacity) {
                            produceNum++;
                            currNum++;
                            System.out.println(Thread.currentThread() + "生产第" + produceNum + "个产品,仓库当前容量" + currNum);
                        } else {
                            System.out.println(Thread.currentThread() + "工厂已满");
                            condition1.await();
                        }
                        condition2.signalAll();
                    } catch (Exception e) {
                        System.out.println(Thread.currentThread() + "生产第" + produceNum + "个产品抛异常!");
                    } finally {
                        lock.unlock();
                    }
                } else {
                    System.out.println(Thread.currentThread() + "生产第" + produceNum + "个产品阻塞!");
                }
            }
            return produceNum;
        }
    }

    public static class Consumer implements Callable<Integer> {
        @Override
        public Integer call() {
            while (consumeNum < sum) {
                boolean hasLock = lock.tryLock();
                if (hasLock) {
                    try {
                        if (currNum > 0) {
                            consumeNum++;
                            currNum--;
                            System.out.println(Thread.currentThread() + "消费第" + consumeNum + "个产品,仓库当前容量" + currNum);
                        } else {
                            System.out.println(Thread.currentThread() + "仓库已消费完毕");
                            condition2.await();
                        }
                        condition1.signalAll();
                    } catch (Exception e) {
                        System.out.println(Thread.currentThread() + "消费第" + consumeNum + "个产品抛异常!");
                    } finally {
                        lock.unlock();
                    }
                } else {
                    System.out.println(Thread.currentThread() + "消费第" + consumeNum + "个产品阻塞!");
                }
            }
            return consumeNum;
        }
    }
}
四、Lock与Condition错误示例
示例一

没有整体放在循环中,导致没有获取锁后就不执行了。

public Integer call() {
    boolean hasLock = lock.tryLock();
    if (hasLock) {
        try {
            while (produceNum < sum) {
                if (currNum < capacity) {
                    produceNum++;
                    currNum++;
                    System.out.println(Thread.currentThread() + "生产第" + produceNum + "个产品!");
                } else {
                    System.out.println(Thread.currentThread() + "工厂已满");
                    condition1.await();
                }
                condition2.signalAll();
            }
            return produceNum;
        } catch (Exception e) {
            LOGGER.error(Thread.currentThread() + "生产第" + produceNum + "个产品抛异常!");
        } finally {
            lock.unlock();
        }
        return produceNum;
    } else {
        LOGGER.error(Thread.currentThread() + "生产第" + produceNum + "个产品阻塞!");
        return produceNum;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值