Java中常见死锁与活锁的实例详解
作者:爬蜥 发布时间:2023-06-26 13:17:00
本文介绍了Java中常见死锁与活锁的实例详解,分享给大家,具体如下:
顺序死锁:过度加锁,导致由于执行顺序的原因,互相持有对方正在等待的锁
资源死锁:多个线程在相同的资源上发生等待
由于调用顺序而产生的死锁
public class Test {
Object leftLock = new Object();
Object rightLock = new Object();
public static void main(String[] args) {
final Test test = new Test();
Thread a = new Thread(new Runnable() {
@Override public void run() {
int i=0;
while (i<10)
{
test.leftRight();
i++;
}
}
},"aThread");
Thread b = new Thread(new Runnable() {
@Override public void run() {
int i=0;
while (i<10)
{
test.rightleft();
i++;
}
}
},"bThread");
a.start();
b.start();
}
public void leftRight(){
synchronized (leftLock){
System.out.println(Thread.currentThread().getName()+":leftRight:get left");
synchronized (rightLock){
System.out.println(Thread.currentThread().getName()+":leftRight:get right");
}
}
}
public void rightleft(){
synchronized (rightLock){
System.out.println(Thread.currentThread().getName()+":rightleft: get right");
synchronized (leftLock){
System.out.println(Thread.currentThread().getName()+":rightleft: get left");
}
}
}
}
运行后输出如下
aThread:leftRight:get left
bThread:rightleft: get right
可以通过jstack发现死锁的痕迹
"bThread" prio=5 tid=0x00007fabb2001000 nid=0x5503 waiting for monitor entry [0x000000011d54b000]
java.lang.Thread.State: BLOCKED (on object monitor)
at main.lockTest.Test.rightleft(Test.java:52)
- waiting to lock <0x00000007aaee5748> (a java.lang.Object)
- locked <0x00000007aaee5758> (a java.lang.Object)
at main.lockTest.Test$2.run(Test.java:30)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"aThread" prio=5 tid=0x00007fabb2801000 nid=0x5303 waiting for monitor entry [0x000000011d448000]
java.lang.Thread.State: BLOCKED (on object monitor)
at main.lockTest.Test.leftRight(Test.java:43)
- waiting to lock <0x00000007aaee5758> (a java.lang.Object)
- locked <0x00000007aaee5748> (a java.lang.Object)
at main.lockTest.Test$1.run(Test.java:19)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
可以看到bThread持有锁0x00000007aaee5758,同时等待0x00000007aaee5748,然而恰好aThread持有锁0x00000007aaee5748并等待0x00000007aaee5758,从而形成了死锁
线程饥饿死锁
public class ExecutorLock {
private static ExecutorService single=Executors.newSingleThreadExecutor();
public static class AnotherCallable implements Callable<String>{
@Override public String call() throws Exception {
System.out.println("in AnotherCallable");
return "annother success";
}
}
public static class MyCallable implements Callable<String>{
@Override public String call() throws Exception {
System.out.println("in MyCallable");
Future<String> submit = single.submit(new AnotherCallable());
return "success:"+submit.get();
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable task = new MyCallable();
Future<String> submit = single.submit(task);
System.out.println(submit.get());
System.out.println("over");
single.shutdown();
}
}
执行的输出只有一行
in MyCallable
通过jstack观察可以看到如下
"main" prio=5 tid=0x00007fab3f000000 nid=0x1303 waiting on condition [0x0000000107d63000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007aaeed1d8> (a java.util.concurrent.FutureTask)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:425)
at java.util.concurrent.FutureTask.get(FutureTask.java:187)
at main.lockTest.ExecutorLock.main(ExecutorLock.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Locked ownable synchronizers:
- None
..
"pool-1-thread-1" prio=5 tid=0x00007fab3f835800 nid=0x5303 waiting on condition [0x00000001199ee000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007ab0f8698> (a java.util.concurrent.FutureTask)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:425)
at java.util.concurrent.FutureTask.get(FutureTask.java:187)
at main.lockTest.ExecutorLock$MyCallable.call(ExecutorLock.java:26)
at main.lockTest.ExecutorLock$MyCallable.call(ExecutorLock.java:20)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00000007aaeed258> (a java.util.concurrent.ThreadPoolExecutor$Worker)
主线程在等待一个FutureTask完成,而线程池中一个线程也在等待一个FutureTask完成。
从代码实现可以看到,主线程往线程池中扔了一个任务A,任务A又往同一个线程池中扔了一个任务B,并等待B的完成,由于线程池中只有一个线程,这将导致B会被停留在阻塞队列中,而A还得等待B的完成,这也就是互相等待导致了死锁的反生
这种由于正在执行的任务线程都在等待其它工作队列中的任务而阻塞的现象称为 线程饥饿死锁
活锁
并未产生线程阻塞,但是由于某种问题的存在,导致无法继续执行的情况。
1、消息重试。当某个消息处理失败的时候,一直重试,但重试由于某种原因,比如消息格式不对,导致解析失败,而它又被重试
这种时候一般是将不可修复的错误不要重试,或者是重试次数限定
2、相互协作的线程彼此响应从而修改自己状态,导致无法执行下去。比如两个很有礼貌的人在同一条路上相遇,彼此给对方让路,但是又在同一条路上遇到了。互相之间反复的避让下去
这种时候可以选择一个随机退让,使得具备一定的随机性
来源:https://segmentfault.com/a/1190000017134766
猜你喜欢
- 人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中?这里浅谈Java中的栈和堆首先,将结论写在前
- 本文实例为大家分享了unity鼠标或者手指点击模型播放动的具体代码,供大家参考,具体内容如下using UnityEngine;using
- 第一次进入应用的时候,都会有一个引导页面,引导页面的实现起来也很简单,实现的方式也有很多,下面是自己写的一个引导页面的效果,大致的实现思路为
- 项目分为前台和后台,前台主要为学生角色、后台主要为管理员角色。管理员添加试题和发布试卷,学生负责在线考试、在线查看成绩和错题记录列表等。管理
- 编写C#程序的时候,我们都遇到过配置文件,而如今绝大多数的配置文件都是用XML写的。所以在处理的时候就需要操作XML文件。那么C#如何操作X
- 在平时做系统项目时,经常会需要做导出功能,不论是导出excel,还是导出cvs文件。我下面的demo是在springmvc的框架下实现的。1
- 前导:发过程中经常会使用java将office系列文档转换为PDF, 一般都使用微软提供的openoffice+jodconverter 实
- javax.el.ELException的解决方式failed to parse the expression [${xxx}]Tomcat
- 使用Aspose.Cells创建和读取Excel文件,供大家参考,具体内容如下1. 创建ExcelAspose.Cells.License
- 题目我们可以用2×1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2×1的小矩形无重叠地覆盖一个2×n的大矩形,总共有多少种方法?程序核心
- 本文实例为大家分享了springboot读取application.yaml文件数据的具体代码,供大家参考,具体内容如下提示:以下是本篇文章
- 本文实例为大家分享了Unity Shader实现黑幕过场效果的具体代码,供大家参考,具体内容如下一、效果演示二、实现Shader:黑幕过场着
- 前言通常在工作中比较常用到的Microsoft Word是属于国外的文档内容编辑软件,其编译技术均属国外。而OFD是一种我国的自主文档格式,
- 本文实例讲述了Android基于SoftReference缓存图片的方法。分享给大家供大家参考,具体如下:Java中的SoftReferen
- 整型变量基本语法格式int变量名= 初始值;代码示例int a = 10;int表示变量的类型是一个整型。在 Java 中, 一个int变量
- 在项目的实际开发和应用中,常常需要用到将对象转为String这一基本功能。本文将对常用的转换方法进行一个总结。常用的方法有Object.to
- 在 Java 语言中的类初始化块 文章中我们简单的介绍了下 Java 中的实例初始化块 ( IIB )。不过我觉得介绍的有点简单了,于是,再
- Bean:在Spring技术中是基于组件的最基本了是最常用的单元其实实例保存在Spring的容器当中Bean通常被定义在配置文件当中,Bea
- 这里简单介绍了一些常用的属性,以及一些术语的解释和举例说明,不太全面,希望读者多多补充。1.重载:函数名相同,参数的个数或参数类型不同; p
- 关于unicode和utf的关系,可以简单的记忆:Unicode是一个编码组织、一个编码规范、在java中指utf-16;utf是Unico