Basically, I have a long task that consists of bunch of sequence sub-tasks as follows:
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);
}
}
What I need is to run only one instance of the Task, and if one Task begins, the other Tasks (if any) should terminate immediately.
I used a single thread executor:
Executor executor = Executors.newSingleThreadExecutor();
and I run the task as:
executor.execute(new Task(foo));
This guarantees that only one task executes at a time, but unfortunately it does not terminate the previous tasks.
However, I decide to use a boolean flag in between each 2 sub-tasks as follows:
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);
}
}
and use it like this:
BooleanHolder bh = new BooleanHolder();
// ...
bh.terminate = true;
executor.execute(new Task(foo, bh));
However, this seems to be inefficient solution and not thread safe. Do you suggest a better solution?
You should use the
ExecutorServiceinterface, instead ofExecutor, like this:You can then interrupt the running task in order to execute another task through the
cancelmethod:As @RPT said however, you should structure your tasks in such a way to respond to interrupts, otherwise the interrupt signal will not have any effect. If your task has no operation which throws an
InterruptedException, you should manually check the interrupt flag from time to time (similar to what you already did):By the way, this solves your problem, but does not actually terminate the thread inside ExecutorService.