基本上,我有一个很长的任务,包括一系列序列子任务,如下所示:
class Task implements Runnable
{
private Foo foo;
public Task(Foo foo)
{
this.foo = foo;
}
@Override
public void run()
{
doTask1(foo);
doTask2(foo);
doTask3(foo);
doTask4(foo);
// ...
doTaskN(foo);
}
}
我需要的是只运行Task
的一个实例,如果一个Task
开始,则其他Task
s(如果有的话)应立即终止。
我使用了单线程执行程序:
Executor executor = Executors.newSingleThreadExecutor();
我将任务运行为:
executor.execute(new Task(foo));
这可以保证一次只执行一个任务,但遗憾的是它不会终止先前的任务。
但是,我决定在每两个子任务之间使用一个布尔标志,如下所示:
class BooleanHolder
{
boolean terminate = false;
}
class Task implements Runnable
{
private Foo foo;
private BooleanHolder bh;
public Task(Foo foo, BooleanHolder bh)
{
this.foo = foo;
this.bh = bh;
}
@Override
public void run()
{
bh.terminate = false;
doTask1(foo);
if(bh.terminate) return;
doTask2(foo);
if(bh.terminate) return;
doTask3(foo);
if(bh.terminate) return;
doTask4(foo);
// ...
if(bh.terminate) return;
doTaskN(foo);
}
}
并像这样使用它:
BooleanHolder bh = new BooleanHolder();
// ...
bh.terminate = true;
executor.execute(new Task(foo, bh));
然而,这似乎是低效的解决方案,而不是线程安全。你建议一个更好的解决方案吗?
答案 0 :(得分:2)
您应该使用ExecutorService
界面,而不是Executor
,如下所示:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(new Task(foo));
然后,您可以中断正在运行的任务,以便通过cancel
方法执行另一项任务:
future.cancel(true);
然而,正如@RPT所说,你应该以一种响应中断的方式构建你的任务,否则中断信号将没有任何效果。如果你的任务没有抛出InterruptedException
的操作,你应该不时手动检查中断标志(类似于你已经做过的):
@Override
public void run()
{
....
if (Thread.interrupted()) {
// Release resources and end task
}
....
}
顺便说一句,这解决了你的问题,但实际上并没有终止ExecutorService中的线程。