0

基本上,我有一个很长的任务,由一堆序列子任务组成,如下所示:

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);
    }
}

我需要的是只运行 s 的一个实例Task,如果一个实例Task开始,另一个Tasks (如果有的话)应该立即终止。

我使用了一个单线程执行器:

Executor executor = Executors.newSingleThreadExecutor();

我将任务运行为:

executor.execute(new Task(foo));

这保证了一次只执行一个任务,但不幸的是它不会终止之前的任务。


但是,我决定在每 2 个子任务之间使用一个布尔标志,如下所示:

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));

但是,这似乎是低效的解决方案并且不是线程安全的。您建议更好的解决方案吗?

4

1 回答 1

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 中的线程。

于 2012-07-16T16:04:28.523 回答