死锁
产生死锁的四个必要条件:
- (1) 互斥条件:一个资源每次只能被一个进程使用。
- (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
产生死锁, 顺序死锁
@Slf4j
public class DeadlockExample {
static Object lockA = new Object();
static Object lockB = new Object();
public static void main(String[] args) {
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name.split("@")[0];
log.info("Pid is:" + pid);
log.info("jstack " + pid);
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(() -> {
synchronized (lockA) {
try {
log.info("lockA");
TimeUnit.SECONDS.sleep(10);
log.info("lockA after sleep");
synchronized (lockB) {
log.info("lock B");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
executorService.submit(() -> {
synchronized (lockB) {
try {
log.info("lockB");
TimeUnit.SECONDS.sleep(10);
log.info("lockB after sleep");
synchronized (lockA) {
log.info("lock A");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
分析信息 Found one Java-level deadlock:
Found one Java-level deadlock:
=============================
"pool-1-thread-1":
waiting to lock monitor 0x000002c99012fa80 (object 0x0000000710944898, a java.lang.Object),
which is held by "pool-1-thread-2"
"pool-1-thread-2":
waiting to lock monitor 0x000002c99012bb80 (object 0x0000000710944888, a java.lang.Object),
which is held by "pool-1-thread-1"
Java stack information for the threads listed above:
===================================================
"pool-1-thread-1":
at cn.wyj.learn.juc.DeadlockExample.lambda$main$0(DeadlockExample.java:33)
- waiting to lock <0x0000000710944898> (a java.lang.Object)
- locked <0x0000000710944888> (a java.lang.Object)
at cn.wyj.learn.juc.DeadlockExample$$Lambda$41/0x00000008000e2440.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(java.base@11.0.2/Executors.java:515)
at java.util.concurrent.FutureTask.run(java.base@11.0.2/FutureTask.java:264)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.2/ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.2/ThreadPoolExecutor.java:628)
at java.lang.Thread.run(java.base@11.0.2/Thread.java:834)
"pool-1-thread-2":
at cn.wyj.learn.juc.DeadlockExample.lambda$main$1(DeadlockExample.java:50)
- waiting to lock <0x0000000710944888> (a java.lang.Object)
- locked <0x0000000710944898> (a java.lang.Object)
at cn.wyj.learn.juc.DeadlockExample$$Lambda$42/0x00000008000e1840.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(java.base@11.0.2/Executors.java:515)
at java.util.concurrent.FutureTask.run(java.base@11.0.2/FutureTask.java:264)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.2/ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.2/ThreadPoolExecutor.java:628)
at java.lang.Thread.run(java.base@11.0.2/Thread.java:834)
Found 1 deadlock.
活锁
指事物1可以使用资源,但它让其他事物先使用资源;事物2可以使用资源,但它也让其他事物先使用资源,于是两者一直谦让,都无法使用资源。
活锁同样会发生在多个相互协作的线程间,当他们为了彼此间的响应而相互礼让,使得没有一个线程能够继续前进,那么就发生了活锁。
好比两个过于礼貌的人在半路相遇,出于礼貌他们相互礼让,避开对方的路,但是在另一条路上又相遇了。就这样,不停地一直避让下去。。。。
@Slf4j
public class DeadlockExample {
static ReentrantLock reentrantLockA = new ReentrantLock();
static ReentrantLock reentrantLockB = new ReentrantLock();
public static void main(String[] args) {
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name.split("@")[0];
log.info("Pid is:" + pid);
log.info("jstack " + pid);
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(() -> {
try {
while (reentrantLockA.tryLock(10, TimeUnit.SECONDS)) {
log.info("A任务重新初始化");
TimeUnit.SECONDS.sleep(1);
boolean locked = reentrantLockB.isLocked();
if (locked) {
reentrantLockA.unlock();
continue;
}
boolean b = reentrantLockB.tryLock(10, TimeUnit.SECONDS);
if (!b) {
reentrantLockA.unlock();
continue;
}
log.info("线程A处理任务");
break;
}
log.info("线程A处理完成");
} catch (InterruptedException e) {
log.error("线程中断", e);
} finally {
reentrantLockB.unlock();
reentrantLockA.unlock();
}
});
executorService.submit(() -> {
try {
while (reentrantLockB.tryLock(10, TimeUnit.SECONDS)) {
log.info("B任务重新初始化");
TimeUnit.SECONDS.sleep(2);
boolean locked = reentrantLockA.isLocked();
if (locked) {
reentrantLockB.unlock();
continue;
}
boolean b = reentrantLockA.tryLock(10, TimeUnit.SECONDS);
if (!b) {
reentrantLockB.unlock();
continue;
}
log.info("线程B处理任务");
break;
}
log.info("线程B处理完成");
} catch (InterruptedException e) {
log.error("线程中断", e);
} finally {
reentrantLockA.unlock();
reentrantLockB.unlock();
}
});
executorService.shutdown();
}
}
10:55:25.434 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:55:25.434 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:55:26.435 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:55:27.436 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:55:29.436 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:55:31.437 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:55:33.438 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
.
.
.
.
.
.
10:57:41.497 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:57:42.493 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:57:43.493 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:57:43.498 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:57:44.493 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:57:45.493 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:57:45.498 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:57:46.494 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
解决活锁1
在锁让出的时候时候添加随机睡眠时间,
@Slf4j
public class DeadlockExample {
static ReentrantLock reentrantLockA = new ReentrantLock();
static ReentrantLock reentrantLockB = new ReentrantLock();
public static void main(String[] args) {
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name.split("@")[0];
log.info("Pid is:" + pid);
log.info("jstack " + pid);
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(() -> {
try {
//自旋
while (reentrantLockA.tryLock(10, TimeUnit.SECONDS)) {
log.info("A任务重新初始化");
TimeUnit.SECONDS.sleep(1);
boolean locked = reentrantLockB.isLocked();
if (locked) {
reentrantLockA.unlock();
//避免活锁
TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(1,2000));
continue;
}
boolean b = reentrantLockB.tryLock(10, TimeUnit.SECONDS);
if (!b) {
reentrantLockA.unlock();
continue;
}
log.info("线程A处理任务");
break;
}
log.info("线程A处理完成");
} catch (InterruptedException e) {
log.error("线程中断", e);
} finally {
reentrantLockB.unlock();
reentrantLockA.unlock();
}
});
executorService.submit(() -> {
try {
//自旋
while (reentrantLockB.tryLock(10, TimeUnit.SECONDS)) {
log.info("B任务重新初始化");
TimeUnit.SECONDS.sleep(2);
boolean locked = reentrantLockA.isLocked();
if (locked) {
reentrantLockB.unlock();
//避免活锁
TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(1, 2000));
continue;
}
boolean b = reentrantLockA.tryLock(10, TimeUnit.SECONDS);
if (!b) {
reentrantLockB.unlock();
continue;
}
log.info("线程B处理任务");
break;
}
log.info("线程B处理完成");
} catch (InterruptedException e) {
log.error("线程中断", e);
} finally {
reentrantLockA.unlock();
reentrantLockB.unlock();
}
});
executorService.shutdown();
}
}
11:28:22.212 [main] INFO cn.wyj.learn.juc.DeadlockExample - Pid is:33004
11:28:22.215 [main] INFO cn.wyj.learn.juc.DeadlockExample - jstack 33004
11:28:22.219 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
11:28:22.219 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
11:28:23.845 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
11:28:24.846 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - 线程A处理任务
11:28:24.846 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - 线程A处理完成
11:28:25.546 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
11:28:27.547 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - 线程B处理任务
11:28:27.547 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - 线程B处理完成
解决活锁2 约定优先级
线程A 是等待10S 才让出所, 线程B如果发现已经被锁定那么立即释放锁
@Slf4j
public class DeadlockExample3 {
static ReentrantLock reentrantLockA = new ReentrantLock();
static ReentrantLock reentrantLockB = new ReentrantLock();
public static void main(String[] args) {
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name.split("@")[0];
log.info("Pid is:" + pid);
log.info("jstack " + pid);
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(() -> {
try {
//自旋
while (reentrantLockA.tryLock(10, TimeUnit.SECONDS)) {
log.info("A任务重新初始化");
TimeUnit.SECONDS.sleep(1);
boolean b = reentrantLockB.tryLock(10, TimeUnit.SECONDS);
if (!b) {
reentrantLockA.unlock();
continue;
}
log.info("线程A处理任务");
break;
}
log.info("线程A处理完成");
} catch (InterruptedException e) {
log.error("线程中断", e);
} finally {
reentrantLockB.unlock();
reentrantLockA.unlock();
}
});
executorService.submit(() -> {
try {
//自旋
while (reentrantLockB.tryLock(10, TimeUnit.SECONDS)) {
log.info("B任务重新初始化");
TimeUnit.SECONDS.sleep(2);
boolean locked = reentrantLockA.isLocked();
if (locked) {
reentrantLockB.unlock();
//避免活锁
TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(1, 2000));
continue;
}
boolean b = reentrantLockA.tryLock(10, TimeUnit.SECONDS);
if (!b) {
reentrantLockB.unlock();
continue;
}
log.info("线程B处理任务");
break;
}
log.info("线程B处理完成");
} catch (InterruptedException e) {
log.error("线程中断", e);
} finally {
reentrantLockA.unlock();
reentrantLockB.unlock();
}
});
executorService.shutdown();
}
}
网友评论