JUC并发编程 活跃性 -- 活锁 & 死锁/活锁的区别 & 饥饿
Posted Z && Y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC并发编程 活跃性 -- 活锁 & 死锁/活锁的区别 & 饥饿相关的知识,希望对你有一定的参考价值。
1. 活锁
活锁出现在两个线程互相改变对方的结束条件,最后谁也无法结束,例如
package tian;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.TestLiveLock")
public class TestLiveLock {
static volatile int count = 10;
static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
// 期望减到 0 退出循环
while (count > 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
log.debug("count: {}", count);
}
}, "t1").start();
new Thread(() -> {
// 期望超过 20 退出循环
while (count < 20) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
log.debug("count: {}", count);
}
}, "t2").start();
}
}
运行结果:
2. 死锁/活锁的区别
死锁:
2个线程互相持有对方想要的锁,导致无法继续向下运行( 2个线程都是阻塞状态 )
活锁:
2个线程都在继续运行,但是由于改变了对方的结束条件,导致2个线程结束不了
3. 饥饿
- 很多教程中把饥饿定义为,一个线程由于优先级太低,始终得不到 CPU 调度执行,也不能够结束,饥饿的情况不易演示,讲读写锁时会涉及饥饿问题
- 下面讲一下遇到的一个线程饥饿的例子,先来看看使用顺序加锁的方式解决之前的死锁问题
package tian;
import lombok.extern.slf4j.Slf4j;
public class TestDeadLock {
public static void main(String[] args) {
Chopstick c1 = new Chopstick("1");
Chopstick c2 = new Chopstick("2");
Chopstick c3 = new Chopstick("3");
Chopstick c4 = new Chopstick("4");
Chopstick c5 = new Chopstick("5");
new Philosopher("苏格拉底", c1, c2).start();
new Philosopher("柏拉图", c2, c3).start();
new Philosopher("亚里士多德", c3, c4).start();
new Philosopher("赫拉克利特", c4, c5).start();
// 顺序加锁 左小右大
new Philosopher("阿基米德", c1, c5).start();
}
}
@Slf4j(topic = "c.Philosopher")
class Philosopher extends Thread {
final Chopstick left;
final Chopstick right;
public Philosopher(String name, Chopstick left, Chopstick right) {
super(name);
this.left = left;
this.right = right;
}
@Override
public void run() {
while (true) {
// 尝试获得左手筷子
synchronized (left) {
// 尝试获得右手筷子
synchronized (right) {
eat();
}
}
}
}
private void eat() {
log.debug("eating...");
}
}
/*
* 筷子类
* */
class Chopstick {
String name;
public Chopstick(String name) {
this.name = name;
}
@Override
public String toString() {
return "筷子{" + name + '}';
}
}
运行结果:
以上是关于JUC并发编程 活跃性 -- 活锁 & 死锁/活锁的区别 & 饥饿的主要内容,如果未能解决你的问题,请参考以下文章
JUC并发编程 活跃性 -- 死锁 & 定位死锁 & 哲学家就餐问题