线程池自引发死锁
-
死锁是由许多线程锁定相同资源引起的
-
如果在该池中运行的任务内使用线程池,也会发生死锁
-
像RxJava / Reactor这样的现代图书馆也很容易受到影响
死锁是两个或多个线程正在等待彼此获取的资源的情况。例如,线程A等待lock1线程B锁定,而线程B等待lock2,由线程A锁定。在最坏的情况下,应用程序冻结无限期的时间。让我向您展示一个具体的例子。想象一下,有一个Lumberjack类可以保存对两个附件锁的引用:
import com.google.common.collect.ImmutableList;
import lombok.RequiredArgsConstructor;
import java.util.concurrent.locks.Lock;
@RequiredArgsConstructor
class Lumberjack {
private final String name;
private final Lock accessoryOne;
private final Lock accessoryTwo;
void cut(Runnable work) {
try {
accessoryOne.lock();
try {
accessoryTwo.lock();
work.run();
} finally {
accessoryTwo.unlock();
}
} finally {
accessoryOne.unlock();
}
}
}
每个伐木工人都需要两个配件:头盔和电锯。在他接近之前work,他必须对这两者保持独占锁定。我们按如下方式创建伐木工人:
import lombok.RequiredArgsConstructor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@RequiredArgsConstructor
class Logging {
private final Names names;
private final Lock helmet = new ReentrantLock();
private final Lock chainsaw = new ReentrantLock();
Lumberjack careful() {
return new Lumberjack(names.getRandomName(), helmet, chainsaw);
}
Lumberjack yolo() {
return new Lumberjack(names.getRandomName(), chainsaw, helmet);
}
}
正如你所看到的那样,有两种伐木工人:首先是头盔,然后是电锯,反之亦然。小心翼翼的伐木工人首先尝试获得头盔,然后等待电锯。YOLO型的伐木工人首先拿电锯然后寻找头盔。让我们生成一些伐木工人并同时运行它们:
rivate List<Lumberjack> generate(int count, Supplier<Lumberjack> factory) {
return IntStream
.range(0, count)
.mapToObj(x -> factory.get())
.collect(toList());
}
generate()是一种创建给定类型的伐木工人集合的简单方法。然后我们生成了一堆细心和yolo伐木工人:
private final Logging logging;
//...
List<Lumberjack> lumberjacks = new CopyOnWriteArr