Java问题记录——IllegalMonitorStateException

摘要:本文主要分析了IllegalMonitorStateException的产生原因。

部分内容来自以下博客:

https://blog.csdn.net/historyasamirror/article/details/6709693

锁对象发生了改变

在测试多线程通信的代码时,出现了这个异常。

代码分析

代码如下:

 public class Demo {
public static void main(String[] args) {
DemoThread demoThread = new DemoThread();
Thread thread1 = new Thread(demoThread);
Thread thread2 = new Thread(demoThread);
thread1.start();
thread2.start();
}
} class DemoThread implements Runnable {
private Integer num = 1; @Override
public void run() {
while (true) {
synchronized (num) {
num.notify();
if (num <= 10) {
System.out.println(Thread.currentThread().getName() + " >>> " + num++);
try {
num.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}

运行结果如下:

 Thread-0 >>> 1
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.iyao.ide.engine.task.DemoThread.run(Demo.java:22)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.iyao.ide.engine.task.DemoThread.run(Demo.java:26)
at java.lang.Thread.run(Thread.java:745)

说明

在网上查找资料,发现需要在调用wait()或者notify()之前,必须使用synchronized语义绑定住被wait/notify的对象。

可问题是,在上面的代码中,已经对num这个变量使用了synchronzied,然后才调用的num.wait()。按理不应该抛出这个异常。

真正的问题在于num这个变量是一个Integer,并且,在调用num.wait()之前,num执行了一次自增操作。

Integer型变量在执行自增的时候,其实是创建了一个新的对象。简单的说,在自增的之前和之后,num并不是同一个对象。

synchronzied(num)绑定的是旧的Integer对象,而num.wait()使用的是新的Integer对象。由于新的Integer对象并没有使用synchronzied进行同步,所以系统抛出了IllegalMonitorStateException异常。

相同的悲剧还有可能出现在num是Boolean或者String类型的时候。

一个解决方案是采用java.util.concurrent.atomic中对应的类型,比如这里就应该是AtomicInteger。采用AtomicInteger类型,可以保证对它的修改不会产生新的对象。

解决方案

代码修改后如下:

 public class Demo {
public static void main(String[] args) {
DemoThread demoThread = new DemoThread();
Thread thread1 = new Thread(demoThread);
Thread thread2 = new Thread(demoThread);
thread1.start();
thread2.start();
}
} class DemoThread implements Runnable {
private AtomicInteger num = new AtomicInteger(1); @Override
public void run() {
while (true) {
synchronized (num) {
num.notify();
if (num.intValue() <= 10) {
System.out.println(Thread.currentThread().getName() + " >>> " + num.getAndAdd(1));
try {
num.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}

运行结果如下:

 Thread-0 >>> 1
Thread-1 >>> 2
Thread-0 >>> 3
Thread-1 >>> 4
Thread-0 >>> 5
Thread-1 >>> 6
Thread-0 >>> 7
Thread-1 >>> 8
Thread-0 >>> 9
Thread-1 >>> 10

结论

在使用锁的时候要注意锁住的对象是谁,是否发生过改变。

Java问题记录——IllegalMonitorStateException的更多相关文章

  1. Java 日志记录规则

    Java 日志记录规则 规则一:日志是面向读者的 我们不应该让无价值的信息使日志文件变得乱糟糟,比如说完整打印所有的实体字段. 通常,实体名字和其逻辑关键字足以识别在表格中的一条记录了. 规则二:匹配 ...

  2. 补充Java面试记录

    补充Java面试记录 背景:这两天面试遇到的部分问题都分散在了前面两篇文摘中,这里再做一些其他的记录,以备不时之需! 一.谈谈你对SpringBoot的理解? SpringBoot简介:SpringB ...

  3. Java问题记录——循环里的二次判断与状态更新

    Java问题记录——循环里的二次判断与状态更新 摘要:本文主要记录了在循环操作时可能出现的问题. 问题重现 在使用循环结构时,如果使用了定时任务,或者代码会多次调用循环结构,可能会导致有些对象会被循环 ...

  4. Java问题记录——OutOfMemoryError

    Java问题记录——OutOfMemoryError 摘要:本文主要分析了OutOfMemoryError的产生原因. 没有分页导致占用大量内存 查看进程 使用 jps 命令查看当前运行的Java进程 ...

  5. SLF4J (The Simple Logging Facade for Java)使用记录

    SLF4J (The Simple Logging Facade for Java)使用记录 官网 http://www.slf4j.org/ 参考资料 官方文档 什么是 SLF4J? 官网: The ...

  6. 【Java】记录一次代码优化

    前不久的项目时间紧张,为了尽快完成原型开发,写了一段效率相当低的代码. 最近几天闲下来,主动把之前的代码优化了一下:)   标签:Java.Mybatis.MySQL 概况:本地系统从另外一个系统得到 ...

  7. 普华永道高级JAVA面试记录

    最近在考虑换个工作 原因?咱能不逗吗? 一面感觉发挥不错  二面之后累觉不爱  基本上浪费了半天的工资(好多钱啊~~~) PWD上海地址在浦东软件园  工作环境说实话没我现在工作的环境好,不过里面的人 ...

  8. Java学习笔记(十九)——Java 日志记录 AND log4j

    [前面的话] 学习的进度应该稍微在快一点. Java日志到了必须学习怎么使用的时候了,因为在项目中要进行使用.基础性文章,选择性阅读. [结构] java日志对调试,记录运行,问题定位都起到了很重要的 ...

  9. Java日志记录的事儿

    一.java日志组件 1.common-logging common-logging是apache提供的一个通用的日志接口.用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的 ...

随机推荐

  1. c# 打印的问题总结

    近期 做了一个打印的类,有一下功能: /// <summary>    /// 打印数据表格的类    /// 2016/05/19 @佳序    /// 功能:    /// 01.自动 ...

  2. webUploader上传大视频文件相关web.config配置

    在webuploader上传大文件时必须配置一下,不然请求后台处理程序时,会请求超时.出现404! <system.web> <httpRuntime maxRequestLengt ...

  3. [转]Eclipse插件开发之基础篇(3) 插件的测试与调试

    原文地址:http://www.cnblogs.com/liuzhuo/archive/2010/08/17/eclipse_plugin_1_1_2.html 1. 使用JUnit对插件进行测试 E ...

  4. rust 高级话题

    目录 rust高级话题 前言 零大小类型ZST 动态大小类型DST 正确的安装方法 结构体 复制和移动 特征对象 引用.生命周期.所有权 生命周期 错误处理 交叉编译 智能指针 闭包 动态分派和静态分 ...

  5. [20190530]oracle Audit文件管理.txt

    [20190530]oracle Audit文件管理.txt --//昨天听课,讲一些oracle相关安全的问题,对方提到audit file的管理,应该引入OS audit,这样目的是仅仅root查 ...

  6. android 电容屏(四):驱动调试之驱动程序分析篇 -- FocalTech

    本人用的触摸屏IC是FocalTech公司的ft5306,是一款i2c的电容屏多点触控芯片.对于它的整体驱动官方已经给了,我们就触摸屏和按键部分的代码做相关说明.说明其中应该注意的地方. 对于所有的i ...

  7. CodeForces - 1007A (思维+双指针)

    题意 https://vjudge.net/problem/CodeForces-1007A 对一个序列重排,使得新的数比原来的数大对应的位置个数最多. 思路 举个栗子,比如1 2 2 3 3 3 3 ...

  8. CodeForces - 1251B (思维+贪心)

    题意 https://vjudge.net/problem/CodeForces-1251B n个01串,可以任意交换任意两个字符串的字符任意次,问最多能有多少个回文串. 思路 分类讨论可以发现规律: ...

  9. 远程控制服务(SSH)之Windows远程登陆Linux主机

    本篇blog同样介绍两种方式进行. 首先进行准备工作: 1.所用到的工具如下: (1)     装有Linux系统的VMware虚拟机*1 (2)     终端连接工具Xshell 6 2.将Wind ...

  10. softmax求导、cross-entropy求导及label smoothing

    softmax求导 softmax层的输出为 其中,表示第L层第j个神经元的输入,表示第L层第j个神经元的输出,e表示自然常数. 现在求对的导数, 如果j=i,   1 如果ji, 2 cross-e ...