我正在开发一个程序,该程序处理大量项目并将每个结果发送到REST服务器。该服务器的速率限制为每小时2000个请求,因此该程序必须在处理两个项目之间暂停一会儿。处理失败的项目应在以后呈现给用户。
一切正常,直到关闭程序后我发现shutdownNow()
无效。 UI关闭,但执行器继续工作。在代码的简要摘要下面。
ExecutorService exec = Executors.newSingleThreadExecutor();
SomeProcessor p = new SomeProcessor();
void process() {
exec.submit(() -> {
Stream<SomeObject> s = ...
List<SomeObject> failed = p.process(s);
// show failed in UI
};
}
void exit() {
exec.shutdownNow();
}
还有SomeProcessor
类:
List<SomeObject> process(Stream<SomeObject> s) {
List<SomeObject> failed = s
.sequential()
.filter(o -> !ignore(o)) // ignore irrelevant items
.peek(o -> pause()) // make sure not to exceed server's rate limit
.filter(o -> !process(o)) // keep items failed to process
.collect(Collectors.asList());
return failed;
}
void pause() {
try {
TimeUnit.MILLISECONDS.sleep(...);
} catch (final InterruptedException e) {
Thread.interrupted();
}
}
boolean process(SomeObject o) {
if (Thread.interrupted()) // make task interruptible
// *** but then what? ***
try {
// process o and send result to server
return true;
} catch (SomeException e) {
return false;
}
}
我猜想shutdownNow()
不能正常工作,因为任务不可中断。因此,我试图使该任务可中断,但我不知道它应该是什么样。有什么想法吗?
还有一个奖金问题。 pause()
方法完成了应做的工作。不过,我还是想使用ScheduledThreadPoolExecutor.scheduleAtFixedRate(.)
之类的东西,但随后要处理任务流。像那样存在吗?
感谢您的帮助!
答案 0 :(得分:1)
查看您的pause
方法:
void pause() {
try {
TimeUnit.MILLISECONDS.sleep(...);
} catch (final InterruptedException e) {
Thread.interrupted();
}
}
您已经在此刻检测到中断,但是通过再次设置线程的中断状态或至少尝试这样做来对此做出反应,因为Thread.interrupted()
应该是Thread.currentThread().interrupt()
才能实现,如果您不希望支持中断,那很好,但是这样做适得其反。它将导致您的下一个sleep
调用立即引发InterruptedException
,您可以使用相同的方式进行处理,依此类推。因此,您不仅要继续处理其余元素,而且要在元素之间保持休眠状态。
将方法更改为
void pause() {
try {
TimeUnit.MILLISECONDS.sleep(...);
} catch (final InterruptedException e) {
throw new IllegalStateException("interrupted");
}
}
中断将以IllegalStateException
终止流操作。为了清楚起见,您可以为此场景定义自己的异常类型(扩展RuntimeException
),以区别于所有其他异常类型。