[英]Own ExecutorService used to create CompletableFuture does not terminate
[英]Why does this CompletableFuture not execute with a shared ExecutorService?
我正在研究一种数据流语言的想法,并且尝试使用执行程序服务将可用线程数限制为系统上的内核数,并创建一个共享线程池。
ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
Function a = new Function("A", service);
Function b = new Function("B", service);
Function c = new Function("C", service);
a.addObserver(b);
a.addObserver(c);
a.change()
A发生了更改,导致其调用了evaluate()
,然后B和C收到通知,他们需要更新并且这样做。
在Function.java
我有:
public class Function implements Func{
private boolean isComplete;
private Set<Func> dependsOn;
private Set<Func> observedBy;
private ExecutorService service;
public Function(String name, ExecutorService service){
observedBy = new HashSet<>();
dependsOn = new HashSet<>();
this.isComplete = false;
this.service = service;
}
public void addObserver(Func f){
observedBy.add(f);
f.addDependency(this);
}
private void evaluate() {
boolean match = dependsOn.stream().allMatch(Func::isComplete);
if (match) {
this.isComplete = false;
// inform each observer that I'm about to start to evaluate
observedBy.forEach(func -> func.onDependentEvaluate(this));
CompletableFuture.runAsync(() -> {
try {
System.out.println("Doing some work");
int sleepTime = (int) (Math.random() * 5000);
System.out.println("Working for " + sleepTime);
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, service).thenRun(this::onComplete);
}
}
public void addDependency(Func f){
dependsOn.add(f);
}
@Override
public void change() {;
evaluate();
}
@Override
public void onComplete() {
this.isComplete = true;
observedBy.forEach((f) -> f.onDependentComplete(this));
}
@Override
public void onDependentEvaluate(Func f) {
}
@Override
public void onDependentComplete(Func func){
evaluate();
}
@Override
public boolean isComplete() {
return this.isComplete;
}
}
当我将service
传递给runAsync
,只有A执行。 如果我不传递service
,而CompletableFuture使用ForkJoin.commonPool,则该图将按我的期望执行。 有其他共享ExecutorService
吗? 有什么想法为什么下一个期货不被执行?
您的问题比您想象的要简单得多。 tl; dr唯一的问题是您没有关闭ExecutorService
,因此程序不会终止。
加长版:在我的环境中,该程序按预期运行,并且任务B
和C
实际上可以运行。 我已经重构了您的代码,以允许我创建AbstractFunction
,使我可以覆盖Function
实际执行的行为,例如
public abstract class AbstractFunction implements Func {
protected boolean isComplete;
protected Set<Func> dependsOn;
protected Set<Func> observedBy;
protected ExecutorService service;
protected String name;
public AbstractFunction(String name, ExecutorService service) {
observedBy = new HashSet<>();
dependsOn = new HashSet<>();
this.isComplete = false;
this.service = service;
this.name = name;
}
public void addObserver(Func f) {
observedBy.add(f);
f.addDependency(this);
}
public void addDependency(Func f) {
dependsOn.add(f);
}
@Override
public void onComplete() {
this.isComplete = true;
observedBy.forEach((f) -> f.onDependentComplete(this));
}
@Override
public boolean isComplete() {
return this.isComplete;
}
@Override
public void change() { }
@Override
public void onDependentEvaluate(Func f) { }
@Override
public void onDependentComplete(Func func) { }
}
因此,您原来的(实际上未更改的) Function
现在是这样的:
public class Function extends AbstractFunction implements Func {
public Function(String name, ExecutorService service) {
super(name, service);
}
protected void evaluate() {
boolean match = dependsOn.stream().allMatch(Func::isComplete);
if (match) {
this.isComplete = false;
// inform each observer that I'm about to start to evaluate
observedBy.forEach(func -> func.onDependentEvaluate(this));
CompletableFuture.runAsync(() -> {
try {
System.out.println("Doing some work");
int sleepTime = (int) (Math.random() * 5000);
System.out.println("Working for " + sleepTime);
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
System.out.println("I was interrupted, my name is: " + name);
e.printStackTrace();
}
}, service).thenRun(this::onComplete);
}
}
@Override
public void change() {
evaluate();
}
@Override
public void onDependentComplete(Func f) {
evaluate();
}
}
给定这个新结构,我创建一个ShutdownFunc
来侦听并在"C"
完成时关闭执行程序服务,即
public class ShutdownFunc extends AbstractFunction {
public ShutdownFunc(String name, ExecutorService service) {
super(name, service);
}
@Override
public void onDependentComplete(Func f) {
System.out.println("Shutting down the system");
try {
service.shutdown();
service.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
当然主要:
public class Main {
public static void main(String... args) {
ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime()
.availableProcessors());
Function a = new Function("A", service);
Function b = new Function("B", service);
Function c = new Function("C", service);
a.addObserver(b);
a.addObserver(c);
Func d = new ShutdownFunc("D", service);
c.addObserver(d);
a.change();
}
}
输出:
Doing some work
Working for 4315
Doing some work
Working for 2074
Doing some work
Working for 2884
Shutting down the system
程序正确等待完成,然后正常终止。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.