2、消费者仅仅在仓储有足够仓储量的时候才能消费,仓储量小于要消费的量则等待。
3、仓库的产品量更新(分消费和生产两种情况,这两种情况都会改变仓储量)后,应该通知等待的消费者去消费。
package com.xujinliang.producer_consumer; /** * 测试程序 * @author jin * */ public class Test { public static void main(String[] args) { Inventory inventory = new Inventory(0,54); Consumer c1 = new Consumer(39, inventory); Consumer c2 = new Consumer(20, inventory); Consumer c3 = new Consumer(30, inventory); Producer p1 = new Producer(11, inventory); Producer p2 = new Producer(12, inventory); Producer p3 = new Producer(13, inventory); Producer p4 = new Producer(14, inventory); Producer p5 = new Producer(15, inventory); Producer p6 = new Producer(16, inventory); Producer p7 = new Producer(9 , inventory); Producer p8 = new Producer(13, inventory); c1.start(); c2.start(); c3.start(); p1.start(); p2.start(); p3.start(); p4.start(); p5.start(); p6.start(); p7.start(); p8.start(); } } package com.xujinliang.producer_consumer; /** * 仓库 * @author jin * */ class Inventory { //public static final int max_size = 40; //最大库存量 public int remaining; //当前库存量 public int max_size; Inventory(int remaining,int max_size) { this.max_size = max_size; this.remaining = remaining; } /** * 生产指定数量的产品 * * @param neednum */ public synchronized void produce(int neednum) { //测试是否需要生产 while (neednum + remaining > max_size) { System.out.println(Thread.currentThread().getName() +": 超量:要生产的产品数量" + neednum + "超过仓库余量" + (max_size - remaining)); try { //当前的生产线程等待 wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //满足生产条件,则进行生产,这里简单的更改当前库存量 remaining += neednum; System.out.println(Thread.currentThread().getName() +": 已经生产了" + neednum + "个产品,现仓储量为" + remaining); //唤醒在此对象监视器上等待的所有线程 notifyAll(); } /** * 消费指定数量的产品 * * @param neednum */ public synchronized void consume(int neednum) { //测试是否可消费 while (remaining < neednum) { System.out.println(Thread.currentThread().getName() +": 不足:要消费的数量" + neednum + "大于库存量" + remaining); try { //当前的生产线程等待 wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //满足消费条件,则进行消费,这里简单的更改当前库存量 remaining -= neednum; System.out.println(Thread.currentThread().getName() +": 已经消费了" + neednum + "个产品,现仓储量为" + remaining); //唤醒在此对象监视器上等待的所有线程 notifyAll(); } } package com.xujinliang.producer_consumer; /** * 生产者 * @author jin * */ class Producer extends Thread { private int neednum; //生产产品的数量 private Inventory inventory; //仓库 Producer(int neednum, Inventory inventory) { this.neednum = neednum; this.inventory = inventory; } public void run() { System.out.println(Thread.currentThread().getName()+"启动"); //生产指定数量的产品 inventory.produce(neednum); } } package com.xujinliang.producer_consumer; /** * 消费者 * @author jin * */ class Consumer extends Thread { private int neednum; //生产产品的数量 private Inventory inventory; //仓库 Consumer(int neednum, Inventory inventory) { this.neednum = neednum; this.inventory = inventory; } public void run() { System.out.println(Thread.currentThread().getName()+"启动");//消费指定数量的产品 inventory.consume(neednum); } }转自博客: http://blog.csdn.net/golden1314521/article/details/24174461
运行结果:
Thread-0启动 Thread-2启动 Thread-0: 不足:要消费的数量39大于库存量0 Thread-2: 不足:要消费的数量30大于库存量0 Thread-1启动 Thread-1: 不足:要消费的数量20大于库存量0 Thread-3启动 Thread-3: 已经生产了11个产品,现仓储量为11 Thread-1: 不足:要消费的数量20大于库存量11 Thread-2: 不足:要消费的数量30大于库存量11 Thread-0: 不足:要消费的数量39大于库存量11 Thread-6启动 Thread-6: 已经生产了14个产品,现仓储量为25 Thread-0: 不足:要消费的数量39大于库存量25 Thread-4启动 Thread-2: 不足:要消费的数量30大于库存量25 Thread-7启动 Thread-7: 已经生产了15个产品,现仓储量为40 Thread-1: 已经消费了20个产品,现仓储量为20 Thread-5启动 Thread-8启动 Thread-2: 不足:要消费的数量30大于库存量20 Thread-10启动 Thread-0: 不足:要消费的数量39大于库存量20 Thread-9启动 Thread-4: 已经生产了12个产品,现仓储量为32 Thread-0: 不足:要消费的数量39大于库存量32 Thread-2: 已经消费了30个产品,现仓储量为2 Thread-9: 已经生产了9个产品,现仓储量为11 Thread-10: 已经生产了13个产品,现仓储量为24 Thread-8: 已经生产了16个产品,现仓储量为40 Thread-5: 已经生产了13个产品,现仓储量为53 Thread-0: 已经消费了39个产品,现仓储量为14
Thread-2启动 Thread-2: 不足:要消费的数量30大于库存量0 Thread-3启动 Thread-3: 已经生产了11个产品,现仓储量为11 Thread-6启动 Thread-6: 已经生产了14个产品,现仓储量为25 Thread-7启动 Thread-2: 不足:要消费的数量30大于库存量25 Thread-7: 已经生产了15个产品,现仓储量为40 Thread-2: 已经消费了30个产品,现仓储量为10 Thread-10启动 Thread-10: 已经生产了13个产品,现仓储量为23 Thread-0启动 Thread-0: 不足:要消费的数量39大于库存量23 Thread-1启动 Thread-1: 已经消费了20个产品,现仓储量为3 Thread-5启动 Thread-5: 已经生产了13个产品,现仓储量为16 Thread-4启动 Thread-0: 不足:要消费的数量39大于库存量16 Thread-4: 已经生产了12个产品,现仓储量为28 Thread-8启动 Thread-8: 超量:要生产的产品数量16超过仓库余量12 Thread-0: 不足:要消费的数量39大于库存量28 Thread-9启动 Thread-9: 已经生产了9个产品,现仓储量为37 Thread-0: 不足:要消费的数量39大于库存量37 Thread-8: 超量:要生产的产品数量16超过仓库余量3可以看出程序最后卡死了。
根据消费驱动生产,同时生产兼顾仓库,如果仓不满就生产,并对每次最大消费量做个限制,这样就不存在此问题了。
package com.xujinliang.deadlock; /** * Java线程、并发和死锁 * @author jin * */ public class Test { public static void main(String[] args) { DeadLock deadlock = new DeadLock(); MyThread t1 = new MyThread(deadlock); MyThread t2 = new MyThread(deadlock); MyThread t3 = new MyThread(deadlock); MyThread t4 = new MyThread(deadlock); t1.start(); t2.start(); t3.start(); t4.start(); } } package com.xujinliang.deadlock; /** * * @author jin * */ class MyThread extends Thread { private DeadLock deadlock; MyThread(DeadLock deadlock) { this.deadlock = deadlock; } @Override public void run() { deadlock.read(); deadlock.write(); } } package com.xujinliang.deadlock; /** * * @author jin * */ class DeadLock { private class Resource {//内部私有类 } //内部私有对象 private Resource resourceA = new Resource(); private Resource resourceB = new Resource(); public void read() { synchronized (resourceA) { System.out.println("read() :" + Thread.currentThread().getName() + "获取了resourceA的锁!"); synchronized (resourceB) { System.out.println("read() :" + Thread.currentThread().getName() + "获取了resourceB的锁!"); } } } //write()方法与 read() 的很重要的区别是:write()方法把resourceB的锁的代码放在了resourceA之前,这是它与read()方法最重要的区别,也是本程序能够形成死锁的根源。 public void write() { // synchronized (resourceB) { System.out.println("write():" + Thread.currentThread().getName() + "获取了resourceB的锁!"); synchronized (resourceA) { System.out.println("write():"+ Thread.currentThread().getName() + "获取了resourceA的锁!"); } } } }
下面是程序执行的几个显示结果,大多数情况下它们都发生了死锁:
read() :Thread-2获取了resourceA的锁! read() :Thread-2获取了resourceB的锁! write():Thread-2获取了resourceB的锁! read() :Thread-0获取了resourceA的锁!
read() :Thread-0获取了resourceA的锁! read() :Thread-0获取了resourceB的锁! write():Thread-0获取了resourceB的锁! write():Thread-0获取了resourceA的锁! read() :Thread-3获取了resourceA的锁! read() :Thread-3获取了resourceB的锁! read() :Thread-2获取了resourceA的锁! write():Thread-3获取了resourceB的锁!
未发生死锁(偶然情况),程序正常结束
read() :Thread-2获取了resourceA的锁! read() :Thread-2获取了resourceB的锁! write():Thread-2获取了resourceB的锁! write():Thread-2获取了resourceA的锁! read() :Thread-0获取了resourceA的锁! read() :Thread-0获取了resourceB的锁! write():Thread-0获取了resourceB的锁! write():Thread-0获取了resourceA的锁! read() :Thread-1获取了resourceA的锁! read() :Thread-1获取了resourceB的锁! write():Thread-1获取了resourceB的锁! write():Thread-1获取了resourceA的锁! read() :Thread-3获取了resourceA的锁! read() :Thread-3获取了resourceB的锁! write():Thread-3获取了resourceB的锁! write():Thread-3获取了resourceA的锁!
public synchronized void methodSync() { //…. }它锁定的是调用这个同步方法对象。也就是说,当特定对象obj1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的类所初始化的另一对象obj2却可以任意调用这个被加了synchronized关键字的方法。
public void methodSync() { synchronized (this) { //….. } }
public void method(Object obj) { synchronized(obj) { //….. } }这时,锁就是obj这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。
{ private byte[] lock = new byte[0]; // 特殊的instance变量 public void method() { synchronized(lock) { //… } } //….. }