线程---生产者消费者模型-synchronized实现

本文探讨了使用synchronized实现Java生产者消费者模型时遇到的问题及解决方案。详细分析了当同步对象不一致导致的IllegalMonitorStateException异常,并引用《java编程思想》中的相关描述。此外,还提到了在实现过程中因使用peek()而非remove()导致的消费异常,说明了正确处理消费元素的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模拟生产者、消费者
  • 一个生产者、一个消费者、仓库容量为1,模拟生产者、消费者通信过程。
  • 思路:
仓库:ArrayList,初始化大小为1。
生产者:当仓库未满的情况下,进行生产,并通知消费者消费;当仓库是满的时候,等待消费者消费后的通知。
消费者:当仓库中不为空的情况下,进行消费,并通知生产者生产;当仓库为空时,等待生产者生产后的通知。
  • 实现:
public class ProducerConsumer0416 {
    //生产者
    static class Producer implements Runnable{
        ArrayList<Integer> arrayList;//仓库
        int NUM = 20;//生产的次数
        public Producer(ArrayList<Integer> arrayList){
            this.arrayList = arrayList;
        }
        @Override
        public void run() {
            while (NUM -- > 0) {
                synchronized (arrayList){
                    //判断仓库是否满了,指定仓库大小为1,所以这里只用给定大小
                    if (arrayList.size() < 1){//未满,生产
                        arrayList.add(1);
                        System.out.println("正在生产");
                        arrayList.notify();//通知消费者消费
                    }else {
                        try {
                            arrayList.wait();//满了,则等待
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    //消费者
    static class Consumer implements Runnable {
        ArrayList<Integer> arrayList;
        int NUM = 20;
        public Consumer(ArrayList<Integer> arrayList){
            this.arrayList = arrayList;
        }
        @Override
        public void run() {
            while (NUM -- > 0) {
                synchronized (arrayList){
                    //判断仓库中是否有产品
                    if (arrayList.size() > 0){
                        arrayList.remove(0);//有产品,则进行消费
                        System.out.println("正在消费");
                        arrayList.notify();//通知生产者生产
                    }else {
                        try {
                            arrayList.wait();//空则等待
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>(1);//仓库
        
        new Thread(new Producer(arrayList)).start();
        new Thread(new Consumer(arrayList)).start();
    }
}
  • 实现2:
一个容器用来作为仓库,仓库用queue队列,来实现;
仓库大小:1;
public class ProducerConsumer0416 {
  	//生产者
    static class Producer1 implements Runnable{
        Container0416 container;
        int NUM = 20;
        public Producer1(Container0416 container){
            this.container = container;
        }
        @Override
        public void run() {
            while (NUM -- > 0) {
                container.produce();
            }
        }
    }

    //消费者
    static class Consumer1 implements Runnable {
        Container0416 container;
        int NUM = 20;
        public Consumer1(Container0416 container){
            this.container = container;
        }
        @Override
        public void run() {
            while (NUM -- > 0) {
                container.consume();
            }
        }
    }

    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        Container0416 container0416 = new Container0416(queue);
        new Thread(new Producer1(container0416)).start();
        new Thread(new Consumer1(container0416)).start();
    }
}
public class Container0416 {
    private Queue<Integer> queue;

    public Container0416(Queue<Integer> queue){
        this.queue = new LinkedList<>();
    }

    public synchronized void produce(){
        if (queue.size() < 1){
            queue.add(1);
            System.out.println("正在生产");
            notify();
        }else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void consume(){
        if (queue.size() > 0){
            queue.remove();
            System.out.println("正在消费");
            notify();
        }else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

  • 同时遇到的问题:程序抛出下面的异常:java.lang.IllegalMonitorStateException
    在这里插入图片描述
    总结了以下几点原因:
  1. 当synchronized修饰的对象是this时,即消费者和生产者中使用的synchronized修饰的都是this(synchronized(this)),程序会抛出不合法的监视器状态异常,因为修饰的this对象不是同一个,加锁的对象是不一致的;
  2. 当调用notify() 和wait()方法时,要对象.wait(),这样使用时就不会出现锁对象不一致而抛出异常;在arrayList.notify()方法调用时使用同步上下文,改为如下:

synchronized (t) {
arraylist.notify();
}

《java编程思想》第四版一书中有描述到:
“线程操作的wait()、notify()、notifyAll()方法只能在同步控制方法或同步控制块内调用。如果在非同步控制方法或控制块里调用,程序能通过编译,但运行的时候,将得到 IllegalMonitorStateException 异常,并伴随着一些含糊信息,比如 ‘当前线程不是拥有者’。其实异常的含义是 调用wait()、notify()、notifyAll()的任务在调用这些方法前必须 ‘拥有’(获取)对象的锁。”

同样在JAVA JDK API文档中也有描述如下:
wait()、notify()、notifyAll()法只应由作为此对象监视器的所有者的线程来调用。
通过以下三种方法之一,线程可以成为此对象监视器的所有者:
通过执行此对象的同步 (Sychronized) 实例方法。
通过执行在此对象上进行同步的 synchronized 语句的正文。
对于 Class 类型的对象,可以通过执行该类的同步静态方法。

  1. 生产者消费者模型实现2时,因为把queue作为仓库,所以在消费者消费时,我调用了queue.peek()方法,同时遇到了生产者只生产一次,消费者可以持续消费的问题,如图
    在这里插入图片描述
    在解决问题的步骤:查看peek()方法的实现,因为queue是LinkedList实例化出的对象,查看LinkedList类下的peek(),相当于这里的是获取操作,相当于get(),而不是将元素删除,所以之后调用了remove()方法来实现:
 public E peek() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值