Resubmitting/scheduling 任务本身的任务 - 这是一个好习惯吗?
Resubmitting/scheduling task from the task itself - is it a good practice?
假设我们有一个预定的执行程序服务:
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(...);
对于某些逻辑,我们想要重试任务执行。下面的做法对我来说好像有点味道,但我不明白为什么:
threadPool.submit(new Runnable() {
@Override
public void run() {
// ...
if (needToBeScheduled()) {
threadPool.schedule(this, delay, TimeUnit.MINUTES);
} else if (needToBeResubmitted()) {
threadPool.submit(this);
}
}
});
我看到的一个明显问题是这段代码无法转换为 lambda:
threadPool.submit(()-> {
// ...
if (needToBeScheduled()) {
threadPool.schedule(this, delay, TimeUnit.MINUTES);
} else if (needToBeResubmitted()) {
threadPool.submit(this);
}
});
^^ 这不会编译,因为我们不能从 lambda 引用 this
。虽然可以通过引入一种产生这样的实例并提供它而不是 this
.
的方法来解决
但这只是我看到的一个缺点。这里还有什么可能导致任何问题吗?也许有更合适的方法?将此逻辑移动到 ThreadPoolExecutor.afterExecute()
(虽然这会导致类型转换...)?
假设对象是无状态的,即 Runnable
实例中没有对象变量。
P.S. 做什么的逻辑(重新安排任务或重新提交或什么都不做)是基于从数据库(或任何外部源)检索的一些信息).所以Runnable
仍然是无状态的,但它会根据其工作的一些结果来计算结果。
老实说,我不喜欢任务(一个简单的独立工作单元)决定它是否应该将自己置于服务中并直接与 ExecutorService
交互的方法。我相信 // ...
是任务应该执行的唯一部分。
我会将 Runnable
转换为 Callable<Boolean>
:
Callable<Boolean> task = () -> {
// ...
return needToBeScheduled; // or sth more complex with several boolean fields
};
而且我肯定会将该逻辑移到任务之外(例如,移到服务方法中):
Future<Boolean> future = threadPool.submit(task);
try {
boolean needToBeScheduled = future.get();
if (needToBeScheduled) {
threadPool.schedule(task, delay, TimeUnit.MINUTES);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
我所说的更复杂的东西是指包含 2 个 boolean
字段的 class。使事情变得懒惰需要 Supplier<Boolean>
秒。
final class TaskResult {
private final Supplier<Boolean> needToBeScheduled;
private final Supplier<Boolean> needToBeResubmitted;
private TaskResult(Supplier<Boolean> needToBeScheduled, Supplier<Boolean> needToBeResubmitted) {
this.needToBeScheduled = needToBeScheduled;
this.needToBeResubmitted = needToBeResubmitted;
}
public static TaskResult of(Supplier<Boolean> needToBeScheduled, Supplier<Boolean> needToBeResubmitted) {
return new TaskResult(needToBeScheduled, needToBeResubmitted);
}
public boolean needToBeScheduled() {
return needToBeScheduled != null && needToBeScheduled.get();
}
public boolean needToBeResubmitted() {
return needToBeResubmitted != null && needToBeResubmitted.get();
}
}
对上面的例子稍作改动,我们有:
Callable<TaskResult> task = () -> {
// ...
return TaskResult.of(() -> needToBeScheduled(), () -> needToBeResubmitted());
};
final Future<TaskResult> future = threadPool.submit(task);
try {
final TaskResult result = future.get();
if (result.needToBeScheduled()) {
threadPool.schedule(task, delay, TimeUnit.MINUTES);
}
if (result.needToBeResubmitted()) {
threadPool.submit(task);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
假设我们有一个预定的执行程序服务:
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(...);
对于某些逻辑,我们想要重试任务执行。下面的做法对我来说好像有点味道,但我不明白为什么:
threadPool.submit(new Runnable() {
@Override
public void run() {
// ...
if (needToBeScheduled()) {
threadPool.schedule(this, delay, TimeUnit.MINUTES);
} else if (needToBeResubmitted()) {
threadPool.submit(this);
}
}
});
我看到的一个明显问题是这段代码无法转换为 lambda:
threadPool.submit(()-> {
// ...
if (needToBeScheduled()) {
threadPool.schedule(this, delay, TimeUnit.MINUTES);
} else if (needToBeResubmitted()) {
threadPool.submit(this);
}
});
^^ 这不会编译,因为我们不能从 lambda 引用 this
。虽然可以通过引入一种产生这样的实例并提供它而不是 this
.
但这只是我看到的一个缺点。这里还有什么可能导致任何问题吗?也许有更合适的方法?将此逻辑移动到 ThreadPoolExecutor.afterExecute()
(虽然这会导致类型转换...)?
假设对象是无状态的,即 Runnable
实例中没有对象变量。
P.S. 做什么的逻辑(重新安排任务或重新提交或什么都不做)是基于从数据库(或任何外部源)检索的一些信息).所以Runnable
仍然是无状态的,但它会根据其工作的一些结果来计算结果。
老实说,我不喜欢任务(一个简单的独立工作单元)决定它是否应该将自己置于服务中并直接与 ExecutorService
交互的方法。我相信 // ...
是任务应该执行的唯一部分。
我会将 Runnable
转换为 Callable<Boolean>
:
Callable<Boolean> task = () -> {
// ...
return needToBeScheduled; // or sth more complex with several boolean fields
};
而且我肯定会将该逻辑移到任务之外(例如,移到服务方法中):
Future<Boolean> future = threadPool.submit(task);
try {
boolean needToBeScheduled = future.get();
if (needToBeScheduled) {
threadPool.schedule(task, delay, TimeUnit.MINUTES);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
我所说的更复杂的东西是指包含 2 个 boolean
字段的 class。使事情变得懒惰需要 Supplier<Boolean>
秒。
final class TaskResult {
private final Supplier<Boolean> needToBeScheduled;
private final Supplier<Boolean> needToBeResubmitted;
private TaskResult(Supplier<Boolean> needToBeScheduled, Supplier<Boolean> needToBeResubmitted) {
this.needToBeScheduled = needToBeScheduled;
this.needToBeResubmitted = needToBeResubmitted;
}
public static TaskResult of(Supplier<Boolean> needToBeScheduled, Supplier<Boolean> needToBeResubmitted) {
return new TaskResult(needToBeScheduled, needToBeResubmitted);
}
public boolean needToBeScheduled() {
return needToBeScheduled != null && needToBeScheduled.get();
}
public boolean needToBeResubmitted() {
return needToBeResubmitted != null && needToBeResubmitted.get();
}
}
对上面的例子稍作改动,我们有:
Callable<TaskResult> task = () -> {
// ...
return TaskResult.of(() -> needToBeScheduled(), () -> needToBeResubmitted());
};
final Future<TaskResult> future = threadPool.submit(task);
try {
final TaskResult result = future.get();
if (result.needToBeScheduled()) {
threadPool.schedule(task, delay, TimeUnit.MINUTES);
}
if (result.needToBeResubmitted()) {
threadPool.submit(task);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}