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自带的 ...
随机推荐
- 证书锁定SSL/TLS Pinning
前言 APP端抓包中, 设置抓包代理后会发现部分APP(如app store.Facebook)直接无法访问,其他部分app又功能正常,为什么呢?这涉及 ssl-pinning,证书锁定. 证书锁定( ...
- iOS多线程比较
.iOS的三种多线程技术 .NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) .以下两点是苹果专门开发的“并发”技术,使得程序员可以不再去关心线程的具体使用问题 ØNS ...
- 使用 gitlab 进行代码管理
这里使用 gitlab 做服务器, 客户端主要使用 git extensions. ============================= gitlab 项目成员类型: ============= ...
- vue中点击按钮复制内容
<el-button type="primary" round size="mini" @click="copyUrl">复制u ...
- [20190930]oracle raw类型转化number脚本.txt
[20190930]oracle raw类型转化number脚本.txt --//写一个简单oracle raw转化number脚本,简单说明:--//输入必须是c1,02 或者 c102,不支持c1 ...
- springboot依赖
springboot依赖整合 <parent> <groupId>org.springframework.boot</groupId> <artifactId ...
- 事务的四大性质:ACID
1. 原子性(Atomicity) 一个原子事务要么完整执行,要么干脆不执行.这意味着,工作单元中的每项任务都必须正确执行.如果有任一任务执行失败,则整个工作单元或事务就会被终止.即此前对数据所作的任 ...
- 01-day-vuex的使用
知识点1===>简单的使用vuex 进行state取值 使用yarn下载 yarn add vuex -D vuex的包叫做 store 跟pages同级 创建store文件夹,文件夹下有sto ...
- JMeter jp@gc - stepping thread group插件
这是一个出单接口压力测试的小例子,了解一下压力测试最最基础的基础.出单接口是用来保险出单的,不需要在UI界面下一步下一步的出单,接口一调数据入库完事~~~.再啰嗦一句接口应该都知道是什么吧?一个完整的 ...
- 【第4题】 什么是https
https是基于http和SSL/TLS实现的一个协议,他可以保证在网络上传输的数据都是加密的,从而保证数据安全. 接下来我们从http协议开始,提出想法并逐步进行分析,最终实现Https. 1. h ...