生产者消费者问题(notify和wait)

使用notify和wait机制实现生产者和消费者

设计:

  • 产品: Product类
  • 产品库: ProductRepository类
  • 生产者线程
  • 消费者线程

Product.java:

public class Product {

    private String name;
    private long productNo;

    public Product(String name, long productNo) {
        this.name = name;
        this.productNo = productNo;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getProductNo() {
        return productNo;
    }

    public void setProductNo(long productNo) {
        this.productNo = productNo;
    }

    @Override
    public String toString() {
        return "Product{" +
                "name='" + name + '\'' +
                ", productNo=" + productNo +
                '}';
    }
}

ProductRepository.java:

public class ProductRepository {

    private Vector<Product> products = new Vector<>();
    private static final int MAX_NUM = 10;

    public void produce(){
        synchronized (products){
            if (products.size() == MAX_NUM){ //如果仓库已经满了
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //products.size() < MAX_NUM 如果仓库还没有满
            Product product = new Product("包子", System.currentTimeMillis());
            products.add(product);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+ " 生产了: "+ product+" ,产品仓库当前数量: "+ products.size());
            //通知等待的消费者来消费
            notify();
        }
    }


    public void consume(){
        synchronized (products){
            if (products.size() == 0){ //产品仓库空了,等待生产者生产
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Product product = products.firstElement();
            products.remove(0);
            System.out.println(Thread.currentThread().getName()+ " 消费了: " + product+" ,产品仓库当前数量: "+ products.size());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //通知生产者生产
            notify();
        }
    }

}

Consumer.java:

public class Consumer implements Runnable {

    private ProductRepository repository;

    public Consumer(ProductRepository repository) {
        this.repository = repository;
    }

    @Override
    public void run() {
        while (true){
            repository.consume();
        }
    }
}

Producer.java:

public class Producer implements Runnable {

    private ProductRepository repository;

    public Producer(ProductRepository repository) {
        this.repository = repository;
    }

    @Override
    public void run() {
        while (true){
            repository.produce();
        }
    }
}
一个生产者,一个消费者

测试类:

public class ProductorConsumerTest {


    /**
     * 一个生产者,一个消费者
     * @throws InterruptedException
     */
    public static void oneProducerAndOneConsumer() throws InterruptedException {
        ProductRepository repository = new ProductRepository();
        Consumer consumer = new Consumer(repository);
        Producer producer = new Producer(repository);
        Thread t1 = new Thread(producer,"producer-A");
        Thread t2 = new Thread(consumer,"consumer-B");
        t1.start();
        t2.start();
        t1.join();
        t2.join(); //join(): 主线程等待t1线程和禾t2线程都执行完
    }
    public static void main(String[] args) throws InterruptedException {
           oneProducerAndOneConsumer();
    }
}

结果:

Exception in thread "producer-A" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at com.gml.pinlor.thread.pcproblem.ProductRepository.produce(ProductRepository.java:33)
    at com.gml.pinlor.thread.pcproblem.Producer.run(Producer.java:17)
    at java.lang.Thread.run(Thread.java:745)
producer-A 生产了: Product{name='包子', productNo=1521786358450} ,产品仓库当前数量: 1
consumer-B 消费了: Product{name='包子', productNo=1521786358450} ,产品仓库当前数量: 0

java.lang.IllegalMonitorStateException是什么鬼?在API中是这么描述的:

Thrown to indicate that a thread has attempted to wait on an object’s monitor or to notify other threads waiting on an object’s monitor without owning the specified monitor(一个线程尝试等待一个对象的监视器,或者去通知其他正在等待对象监视器线程,却没有指明一个具体的监视器,才会抛出这个异常)

原来是将synchronized监视到products对象上了,但调用waitnotify方法却不是products对象,将ProductRepository.java换成:

public class ProductRepository {

    private Vector<Product> products = new Vector<>();
    private static final int MAX_NUM = 10;

    public void produce(){
        synchronized (products){
            if (products.size() == MAX_NUM){ //如果仓库已经满了
                try {
                    products.wait();      //让products等待!!!
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //products.size() < MAX_NUM 如果仓库还没有满
            Product product = new Product("包子", System.currentTimeMillis());
            products.add(product);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+ " 生产了: "+ product+" ,产品仓库当前数量: "+ products.size());
            //通知等待的消费者来消费
            products.notify();
//            products.notifyAll();
        }
    }


    public void consume(){
        synchronized (products){
            if (products.size() == 0){ //产品仓库空了,等待生产者生产
                try {
                    products.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Product product = products.firstElement();
            products.remove(0);
            System.out.println(Thread.currentThread().getName()+ " 消费了: " + product+" ,产品仓库当前数量: "+ products.size());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //通知生产者生产
            products.notify();
//            products.notifyAll();
        }
    }

}

结果:

producer-A 生产了: Product{name='包子', productNo=1521786975941} ,产品仓库当前数量: 1
consumer-B 消费了: Product{name='包子', productNo=1521786975941} ,产品仓库当前数量: 0
producer-A 生产了: Product{name='包子', productNo=1521786978944} ,产品仓库当前数量: 1
producer-A 生产了: Product{name='包子', productNo=1521786979944} ,产品仓库当前数量: 2
producer-A 生产了: Product{name='包子', productNo=1521786980944} ,产品仓库当前数量: 3
producer-A 生产了: Product{name='包子', productNo=1521786981945} ,产品仓库当前数量: 4
producer-A 生产了: Product{name='包子', productNo=1521786982945} ,产品仓库当前数量: 5
consumer-B 消费了: Product{name='包子', productNo=1521786978944} ,产品仓库当前数量: 4
consumer-B 消费了: Product{name='包子', productNo=1521786979944} ,产品仓库当前数量: 3
一个生产者,多个消费者

只需要在ProductRepository中将produce方法中products.notify()方法换成products.notifyAll()方法即可

public class ProductRepository {

    private Vector<Product> products = new Vector<>();
    private static final int MAX_NUM = 10;

    public void produce(){
        synchronized (products){
            if (products.size() == MAX_NUM){ //如果仓库已经满了
                try {
                    products.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //products.size() < MAX_NUM 如果仓库还没有满
            Product product = new Product("包子", System.currentTimeMillis());
            products.add(product);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+ " 生产了: "+ product+" ,产品仓库当前数量: "+ products.size());
            //通知等待的消费者来消费
//            products.notify();
            products.notifyAll();
        }
    }


    public void consume(){
        synchronized (products){
            if (products.size() == 0){ //产品仓库空了,等待生产者生产
                try {
                    products.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Product product = products.firstElement();
            products.remove(0);
            System.out.println(Thread.currentThread().getName()+ " 消费了: " + product+" ,产品仓库当前数量: "+ products.size());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //通知生产者生产
            products.notify();
//            products.notifyAll();
        }
    }
}

测试:

public class ProductorConsumerTest {

    /**
     * 一个生产者,多个消费者
     * @throws InterruptedException
     */
    public static void oneProducerAndMoreConsumer() throws InterruptedException {
        ProductRepository repository = new ProductRepository();
        Consumer consumer = new Consumer(repository);
        Consumer consumer2 = new Consumer(repository);
        Producer producer = new Producer(repository);
        Thread t1 = new Thread(producer,"producer-A");
        Thread t2 = new Thread(consumer,"consumer-B");
        Thread t3 = new Thread(consumer,"consumer-C");
        t1.start();
        t2.start();
        t3.start();
        t1.join();
        t2.join();
        t3.join();
    }
    public static void main(String[] args) throws InterruptedException {
 //        oneProducerAndOneConsumer();
         oneProducerAndMoreConsumer();
 //        moreProducerAndMoreConsumer();
     }
}

结果:

producer-A 生产了: Product{name='包子', productNo=1521787226868} ,产品仓库当前数量: 1
producer-A 生产了: Product{name='包子', productNo=1521787227868} ,产品仓库当前数量: 2
producer-A 生产了: Product{name='包子', productNo=1521787228868} ,产品仓库当前数量: 3
producer-A 生产了: Product{name='包子', productNo=1521787229868} ,产品仓库当前数量: 4
producer-A 生产了: Product{name='包子', productNo=1521787230868} ,产品仓库当前数量: 5
producer-A 生产了: Product{name='包子', productNo=1521787231868} ,产品仓库当前数量: 6
producer-A 生产了: Product{name='包子', productNo=1521787232868} ,产品仓库当前数量: 7
producer-A 生产了: Product{name='包子', productNo=1521787233868} ,产品仓库当前数量: 8
producer-A 生产了: Product{name='包子', productNo=1521787234868} ,产品仓库当前数量: 9
producer-A 生产了: Product{name='包子', productNo=1521787235868} ,产品仓库当前数量: 10
consumer-C 消费了: Product{name='包子', productNo=1521787226868} ,产品仓库当前数量: 9
consumer-C 消费了: Product{name='包子', productNo=1521787227868} ,产品仓库当前数量: 8
consumer-B 消费了: Product{name='包子', productNo=1521787228868} ,产品仓库当前数量: 7
consumer-C 消费了: Product{name='包子', productNo=1521787229868} ,产品仓库当前数量: 6
consumer-C 消费了: Product{name='包子', productNo=1521787230868} ,产品仓库当前数量: 5
producer-A 生产了: Product{name='包子', productNo=1521787246869} ,产品仓库当前数量: 6
多个生产者,多个消费者

同样只需要修改ProductRepository中的consumer方法中的products.notity()products.notifyAll(),通知所有的生产者

public class ProductRepository {

    private Vector<Product> products = new Vector<>();
    private static final int MAX_NUM = 10;

    public void produce(){
        synchronized (products){
            if (products.size() == MAX_NUM){ //如果仓库已经满了
                try {
                    products.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //products.size() < MAX_NUM 如果仓库还没有满
            Product product = new Product("包子", System.currentTimeMillis());
            products.add(product);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+ " 生产了: "+ product+" ,产品仓库当前数量: "+ products.size());
            //通知等待的消费者来消费
//            products.notify();
            products.notifyAll();
        }
    }


    public void consume(){
        synchronized (products){
            if (products.size() == 0){ //产品仓库空了,等待生产者生产
                try {
                    products.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Product product = products.firstElement();
            products.remove(0);
            System.out.println(Thread.currentThread().getName()+ " 消费了: " + product+" ,产品仓库当前数量: "+ products.size());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //通知生产者生产
//            products.notify();
            products.notifyAll();
        }
    }

}

测试:

public class ProductorConsumerTest {

    /**
     * 多个生产者,多个消费者
     * @throws InterruptedException
     */
    public static void moreProducerAndMoreConsumer() throws InterruptedException {
        ProductRepository repository = new ProductRepository();
        Consumer consumer = new Consumer(repository);
        Consumer consumer1 = new Consumer(repository);
        Producer producer = new Producer(repository);
        Producer producer1 = new Producer(repository);
        Thread t1 = new Thread(producer,"producer-A");
        Thread t2 = new Thread(consumer,"consumer-B");
        Thread t3 = new Thread(consumer1,"consumer-C");
        Thread t4 = new Thread(producer1,"producer-D");
        t1.start();
        t4.start();
        t2.start();
        t3.start();

        t1.join();
        t4.join();
        t2.join();
        t3.join();
    }

    public static void main(String[] args) throws InterruptedException {
       // oneProducerAndOneConsumer();
        // oneProducerAndMoreConsumer();
       moreProducerAndMoreConsumer();
    }
}

结果:

producer-A 生产了: Product{name='包子', productNo=1521787607751} ,产品仓库当前数量: 1
producer-A 生产了: Product{name='包子', productNo=1521787608752} ,产品仓库当前数量: 2
producer-A 生产了: Product{name='包子', productNo=1521787609752} ,产品仓库当前数量: 3
producer-A 生产了: Product{name='包子', productNo=1521787610752} ,产品仓库当前数量: 4
producer-A 生产了: Product{name='包子', productNo=1521787611753} ,产品仓库当前数量: 5
producer-A 生产了: Product{name='包子', productNo=1521787612753} ,产品仓库当前数量: 6
producer-A 生产了: Product{name='包子', productNo=1521787613753} ,产品仓库当前数量: 7
producer-A 生产了: Product{name='包子', productNo=1521787614753} ,产品仓库当前数量: 8
producer-D 生产了: Product{name='包子', productNo=1521787615753} ,产品仓库当前数量: 9
producer-D 生产了: Product{name='包子', productNo=1521787616753} ,产品仓库当前数量: 10
consumer-C 消费了: Product{name='包子', productNo=1521787607751} ,产品仓库当前数量: 9
consumer-B 消费了: Product{name='包子', productNo=1521787608752} ,产品仓库当前数量: 8
consumer-B 消费了: Product{name='包子', productNo=1521787609752} ,产品仓库当前数量: 7
consumer-B 消费了: Product{name='包子', productNo=1521787610752} ,产品仓库当前数量: 6
consumer-C 消费了: Product{name='包子', productNo=1521787611753} ,产品仓库当前数量: 5
consumer-C 消费了: Product{name='包子', productNo=1521787612753} ,产品仓库当前数量: 4
consumer-C 消费了: Product{name='包子', productNo=1521787613753} ,产品仓库当前数量: 3
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值