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

必要なのは、の1つのインスタンスのみを実行することです。Task一方Taskが開始された場合、もう一方Taskのインスタンス(存在する場合)はすぐに終了する必要があります。

シングルスレッドエグゼキュータを使用しました:

Executor executor = Executors.newSingleThreadExecutor();

そして私は次のようにタスクを実行します:

executor.execute(new Task(foo));

これにより、一度に1つのタスクのみが実行されることが保証されますが、残念ながら、前のタスクは終了しません。


ただし、次のように、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 に答える