Java问题记录——IllegalMonitorStateException
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的更多相关文章
- Java 日志记录规则
Java 日志记录规则 规则一:日志是面向读者的 我们不应该让无价值的信息使日志文件变得乱糟糟,比如说完整打印所有的实体字段. 通常,实体名字和其逻辑关键字足以识别在表格中的一条记录了. 规则二:匹配 ...
- 补充Java面试记录
补充Java面试记录 背景:这两天面试遇到的部分问题都分散在了前面两篇文摘中,这里再做一些其他的记录,以备不时之需! 一.谈谈你对SpringBoot的理解? SpringBoot简介:SpringB ...
- Java问题记录——循环里的二次判断与状态更新
Java问题记录——循环里的二次判断与状态更新 摘要:本文主要记录了在循环操作时可能出现的问题. 问题重现 在使用循环结构时,如果使用了定时任务,或者代码会多次调用循环结构,可能会导致有些对象会被循环 ...
- Java问题记录——OutOfMemoryError
Java问题记录——OutOfMemoryError 摘要:本文主要分析了OutOfMemoryError的产生原因. 没有分页导致占用大量内存 查看进程 使用 jps 命令查看当前运行的Java进程 ...
- SLF4J (The Simple Logging Facade for Java)使用记录
SLF4J (The Simple Logging Facade for Java)使用记录 官网 http://www.slf4j.org/ 参考资料 官方文档 什么是 SLF4J? 官网: The ...
- 【Java】记录一次代码优化
前不久的项目时间紧张,为了尽快完成原型开发,写了一段效率相当低的代码. 最近几天闲下来,主动把之前的代码优化了一下:) 标签:Java.Mybatis.MySQL 概况:本地系统从另外一个系统得到 ...
- 普华永道高级JAVA面试记录
最近在考虑换个工作 原因?咱能不逗吗? 一面感觉发挥不错 二面之后累觉不爱 基本上浪费了半天的工资(好多钱啊~~~) PWD上海地址在浦东软件园 工作环境说实话没我现在工作的环境好,不过里面的人 ...
- Java学习笔记(十九)——Java 日志记录 AND log4j
[前面的话] 学习的进度应该稍微在快一点. Java日志到了必须学习怎么使用的时候了,因为在项目中要进行使用.基础性文章,选择性阅读. [结构] java日志对调试,记录运行,问题定位都起到了很重要的 ...
- Java日志记录的事儿
一.java日志组件 1.common-logging common-logging是apache提供的一个通用的日志接口.用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的 ...
随机推荐
- 配置git远程连接gitlab
1.本地git下载 2.配置全局的用户名和邮箱,命令分别为 git config --global user.name "username" git config --global ...
- arcgis api for javascript 学习(二) 发布并调用地图切片
文章将从发布切片地图到调用切片地图整个过程都展示出来. (一).切片地图的发布 1.还是前面的arcgis展示的地图 2.与发布动态地图前面的步骤是一样的 打开分享后,如图 3.一切就绪后,到达缓存的 ...
- 彻底解决Python3写爬虫或网站时的乱码问题
第一次写贴子,试试水 很多玩Python3的都会遇到编码问题,如果直接去处理未知编码的网页,不是Python内部编码格式utf8会出现乱码,下面介绍一种将未知编码的字串转换为utf8来避免乱码的方法, ...
- stl源码学习(版本2.91)--list
stl源码学习(版本2.91)--list 一,阅读list()构造函数的收获 1,默认构造函数的作用和被调用的时机 struct no{ no(int i){} //no(){ // std::co ...
- [Go] gocron源码阅读-flag包实现命令行参数获取
调用flag包可以方便的获取到命令行中传递的参数,比如可以实现类似nginx执行程序获取命令行参数执行不同操作的目标 package main import ( "flag" &q ...
- metasploit篇
第一部分:基本使用 1.在kali中metasploit默认使用postgresql作为它的数据库: /etc/init.d/postgresql start 开机自启:update-rc.d pos ...
- NGINX动态增加模块,平滑升级
这是一个小心活,不过,多操作几次,也就熟悉了. 参考URL: https://segmentfault.com/a/1190000006755963 一,安装nginx依赖包. yum install ...
- 浅谈[].slice.call(arguments, 1)
今天在跟踪调试项目的代码时,发现在一个function中用到了这么一段[].slice.call(arguments, 1) 的代码.心中便起了疑惑,对于slice 和 call 的方法,倒是不怎么陌 ...
- idea插件(mybatis框架下mapper接口快速跳转对应xml文件)亲测好用!
我相信目前在绝大部分公司里,主要使用的框架是S(spring)S(spring MVC)M(mybatis),其中mybatis总体架构是编写mapper接口,框架扫描其对应的mapper.xml文件 ...
- C++ trais技术 模板特化的应用
// traits 的应用 /////////////////////////////////////////// // traits template <typename T> clas ...