在另一个线程启动时终止一个线程

时间:2012-07-16 15:29:01

标签: java multithreading synchronization thread-safety

基本上,我有一个很长的任务,包括一系列序列子任务,如下所示:

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

然而,这似乎是低效的解决方案,而不是线程安全。你建议一个更好的解决方案吗?

1 个答案:

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