IllegalMonitorStateException异常 | 生产者消费者模式

2023-05-16

文章目录

        • 结论先行:
            • 生产者消费者-synchronized版
            • 生产者消费者-Lock版

结论先行:

在这里插入图片描述这是JDK对这异常的定义。就是说线程没有拿到对应对象的监视器,也就不能在监视器上完成wait或者notify等操作。
解决办法:
加上synchronized,线程就能拿到对象的监视器了。我的理解就是通过synchronized让线程拿到了对象锁,锁定了这个对象,那这个对象的监视器我耍耍问题不大吧。(手动狗头)

另:下面会继续讲解出错的整个过程,以及生产者消费者模式的两种实现方式。


生产者消费者-synchronized版

出错版本:

public class Producter {
    public static void main(String[] args) {
        PandA pandA = new PandA();

        new Thread(()->{
            pandA.increment();
        },"A").start();

        new Thread(()->{
            pandA.increment();
        },"B").start();
    }

}


class PandA{
    private int num = 0;

    public void increment(){
        if (num != 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        num++;
        this.notify();
        System.out.println(Thread.currentThread().getName()+"生产了一个汉堡");

    }

    public void decrement(){
        if (num == 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        num--;
        this.notify();
        System.out.println(Thread.currentThread().getName()+"消费了一个汉堡");

    }

}

运行报错的异常就是IllegalMonitorStateException。原因就是线程没有拿到对象的监视器。所以可以简单记忆,调用wait时请搭配上synchronized。

正确版本:

public class Producter {
    public static void main(String[] args) {
        PandA pandA = new PandA();

        new Thread(()->{
            for (int i=0;i<15;i++){
                pandA.increment();
            }

        },"A").start();

        new Thread(()->{
            for (int i=0;i<15;i++){
                pandA.decrement();
            }

        },"B").start();
    }

}


class PandA{
    private int num = 0;

    public synchronized void increment(){
        while (num != 0){
            try {
                //这个this就是这个对象,不是这个线程,我理解错了。wait(),notify()都是继承自Object的方法
                //this.wait()让当前对象的调用者线程休眠去了
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        num++;
        this.notify();
        System.out.println(Thread.currentThread().getName()+"生产了一个汉堡"+num);

    }

    public synchronized void decrement(){
        while (num == 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        num--;
        this.notify();
        System.out.println(Thread.currentThread().getName()+"消费了一个汉堡"+num);

    }

}
生产者消费者-Lock版

同样先给个错误版本:

public class ProducterLock {
    public static void main(String[] args) {
        test t = new test();
        new Thread(()->{
            for (int i=0;i<15;i++){
                t.increments();
            }
        },"A").start();

        new Thread(()->{
            for (int i=0;i<15;i++){
                t.decrements();
            }
        },"B").start();

    }
}

class test{
    private int num = 0;
    private Lock lock = new ReentrantLock();

    public void increments(){
        lock.lock();
        while(num != 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"生产了一个汉堡"+num);
        lock.unlock();
    }

    public void decrements(){
        {
            lock.lock();
            while(num == 0){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            num++;
            System.out.println(Thread.currentThread().getName()+"消费了一个汉堡"+num);
            lock.unlock();
        }

    }
}

**运行结果:**同样会报IllegalMonitorStateException异常,但这次就有疑问了,我们加了Lock锁啊,没有锁住对象?继续去翻看JDK,找到ReentrantLock,看一下方法会发现一个方法:
在这里插入图片描述在这里插入图片描述在这里插入图片描述

Condition的定义,以及Condition提供的方法。我的疑问也到了解释,监视器方法wait等根本不适合Lock,和Lcok配套的是Condition,他们取代了synchronized和监视器方法的一整套实现方案。

正确代码:

public class ProducterLock {
    public static void main(String[] args) {
        test t = new test();
        new Thread(()->{
            for (int i=0;i<15;i++){
                t.increments();
            }
        },"A").start();

        new Thread(()->{
            for (int i=0;i<15;i++){
                t.decrements();
            }
        },"B").start();

    }
}

class test{
    private int num = 0;
    private Lock lock = new ReentrantLock();

    Condition condition = lock.newCondition();

    public void increments(){
        lock.lock();
        while(num != 0){
            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        num++;
        condition.signal();
        System.out.println(Thread.currentThread().getName()+"生产了一个汉堡"+num);
        lock.unlock();
    }

    public void decrements(){
        {
            lock.lock();
            while(num == 0){
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            num--;
            condition.signal();
            System.out.println(Thread.currentThread().getName()+"消费了一个汉堡"+num);
            lock.unlock();
        }
    }
}

上面代码正确的输出结果如图:
在这里插入图片描述
对了,两种方法Lock版本会好一点,因为Condition可以实现精准通知唤醒。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IllegalMonitorStateException异常 | 生产者消费者模式 的相关文章

随机推荐

  • 如何对singleInstance的Activity多次传入Intent

    在作Notification传Intent数据给Activity时 xff0c 此Activity为singleInstance AndroidManifest xml activity属性 android launchMode 61 34
  • Activity启动模式和onNewIntent调用时机

    文章目录 onNewIntent 的调用时机四种启动模式 onNewIntent 的调用时机 在了解onNewIntent 的调用时机之前 xff0c 我们首先需要对Android中Activity的加载模式做一个了解 xff1a 在And
  • 升级AndroidStudio3.1.4之后Module添加不上问题解决

    AndroidStudio的每次大的升级都会遇到一大堆 莫名其妙 的坑 xff0c 这次从2 3版本直接升级到3 1 4版本之后 xff0c 更是踩坑无数 xff0c 其中就有添加Module的问题 xff0c Import进去之后 xff
  • linux安装java一步一步超详细教程

    一 进入到下载目录 cd usr local src 二 下载Java 下载地址 Java Downloads Oracle 下载完后执行下面这个命令然后选择到下载的文件后通过xshell上传上去 或者通过其他软件上传到服务器 usr lo
  • Android源码预制基础

    1 调用mk生效 call inherit product if exists DEVICE SOURCES preinstall preinstall mk call inherit product if exists DEVICE SO
  • Linux下更新curl版本

    一 前景 由于低版本的curl存在一定的漏洞 xff0c 会对我们的服务器安全造成问题 xff0c 所以 xff0c 我们需要将curl由低版本安装到高版本 二 步骤 1 首先检测服务器安装的curl版本 curl version 2 查看
  • Android广播发送机制剖析【android广播系列二】

    上篇博客大致说了说广播的注册机制 xff0c 动态注册和静态注册广播的原理还不一样 xff0c 动态广播最后HashMap中了 xff0c 最后放到mReceiverResolver中 xff0c 以后当ActivityManagerSer
  • 观察者模式--Java设计模式

    观察者模式定义 xff1a 定义了对象之间的一对多的依赖 xff0c 这样一来 xff0c 当一个对象发生改变状态的时候 xff0c 它的所有依赖者都会收到通知并自动更新 参考如下图 xff1a 观察者设计模式也叫发布 订阅模式 也可以称作
  • Android——RuntimePermission介绍

    1 介绍 androidM版本上 xff0c 对permission的管理做了部分改动 xff0c 针对dangerous permission xff0c 不在安装的时候给予权限 xff0c 而是在运行过程中咨询用户是否给予app响应的权
  • Android中launcherMode="singleTask"详解【android源码解析六】

    android中launcherMode有4中属性 xff1a standard 默认 xff0c singleTop xff0c singleTask和 singleInstance xff1b 网上有好多例子讲解这四种关系的 xff1a
  • Android闹钟最终版【android源码闹钟解析】

    我以前写了个复杂闹钟的demo xff0c 参见 Android闹钟 复杂版 大明进化十五 但是里面的bug有一些 xff0c 好多人留言 xff0c 所以我就看看源码 xff0c 找找原因 xff1f 顺便把源码代码整理出来 xff0c
  • Smali--Dalvik虚拟机指令语言-->【android_smali语法学习一】

    最近一周在研究rom移植 xff0c 所以就对Smali语言学习了一下 xff0c Smali语言其实就是Davlik的寄存器语言 xff1b Smali语言就是android的应用程序 apk通过apktool反编译出来的都有一个smal
  • android4.0自定义锁屏总结【android锁屏研究一】

    最近搬家了 xff0c 从北京 gt 深圳 xff0c 除了天气有点不同外 xff0c 其他的都差不多 xff0c 工作性质和以前也类似 xff01 纪念一下自己的迁移 题外话 转载请表明出处 xff1a http blog csdn ne
  • Android(6.0、7.0、8.0) popupWindow弹窗位置错乱解决方案

    问题描述 xff1a 项目中做一个底部弹窗选择地址的功能 xff0c 直接用的PopupWindow xff0c 简单方便 xff0c 但是却不慎入坑 要求效果 xff0c 如下图 xff1a 就是这么一个简单的底部弹窗 xff0c 点击家
  • android系统锁屏详解【android锁屏解析二】

    谷歌的代码写的确实不错 xff0c 我很幸运 xff0c 一开始接触代码就赶上了谷歌这个开源的系统 xff0c 让我的视野开阔了很多 xff0c 也让我看到了优秀的代码工程师写到的代码 心怀感恩之心 题记 我的有篇文章说了这个锁屏 xff0
  • <转载>创建第一个Android项目

    Android 如何创建项目 Android Hai的博客 CSDN博客 android新建项目 目录一 创建流程二 Android Studio 主窗口三 链接一 创建流程1 安装最新版 Android Studio 2 第一次打开And
  • kotlin---使用注释处理的 Android 框架

    在日常 Android 开发中 xff0c 流行着数以千计的框架帮助我们提升开发效率 使用 Kotlin 开发时仍然可以沿用这些框架 xff0c 而且和使用 Java 同样简单 本章教程将提供相关示例并重点介绍配置的差异 教程以 Dagge
  • 集合的使用——超市购物小票案例

    集合的使用 超市购物小票案例 1 定义GoodsItem类 名称 货号 单价 数量 计价单位 金额 span class token comment 定义GoodsItem类 名称 货号 单价 数量 计价单位 金额 span span cl
  • 在Eclipse中添加sun.misc.Launcher类

    研究类加载器 xff0c 用到sun misc Launcher类 xff0c 如何在Eclipse中添加呢 xff1f 启动类加载器的加载路径 URL ruls 61 sun misc Launcher getBootstrapClass
  • IllegalMonitorStateException异常 | 生产者消费者模式

    文章目录 结论先行 xff1a 生产者消费者 synchronized版生产者消费者 Lock版 结论先行 xff1a 这是JDK对这异常的定义 就是说线程没有拿到对应对象的监视器 xff0c 也就不能在监视器上完成wait或者notify