0

Scenario

I have this class, let's say Foo, whose only job is to sequentially execute a set of tasks. Sounds simple, right? Well, all of these tasks are executed in their own separate thread. Instead of simply calling Thread.join() on each task to ensure sequential execution, it uses a ReentrantLock and Condition. For instance,

public class Foo
{
    private final Lock lock;
    private final Condition condition;
    private Future<?> task;

    public Foo()
    {
        lock = new ReentrantLock();
        condition = lock.newCondition();

        run();
    }

    /**
     * Runs Foo
     */
    public void run()
    {
        Runnable runnable = new Runnable()
        {
            @Override
            public void run()
            {
                lock.lock();
                try
                {
                    // do tasks
                }
                finally
                {
                    lock.unlock();
                }

            }
        };

        // Submit task
        task = Executors.newSingleThreadExecutor().submit(runnable);
    }

    /**
     * Blocks execution until signal is received
     */
    public void waitForNotification()
    {
        try
        {
            condition.await();
        }
        catch (InterruptedException e)
        {
        }
    }

    /**
     * Gets the lock
     * 
     * @return Lock
     */
    public final Lock getLock()
    {
        return lock;
    }

    /**
     * Gets the condition
     * 
     * @return Condition
     */
    public final Condition getCondition()
    {
        return condition;
    }

    /**
     * Gets the sender's task
     * 
     * @return Task
     */
    public Future<?> getTask()
    {
        return task;
    }
}

After every task, waitForNotification() is called and waits for another class, let's say Bar, to wake it up. The only job for Bar is to handle a response that informs the application whether the task has passed or failed. That being said, it will do one of two things:

  1. Cancel the thread altogether (i.e. getTask().cancel)
  2. Wake the thread (i.e. getCondition().signal)

Item 2 works just fine, but Item 1 doesn't. For instance,

public class Bar
{
    private Foo foo;

    // doesn't work!
    public void handleFailed()
    {
        // Cancel task
        foo.getTask().cancel(true)
    }

    public void handlePassed()
    {
         // Signal waiting Foo
         foo.getLock().lock();
         try
         {
            foo.getCondition().signal();
         }
         finally
         {
            foo.getLock().unlock();
         }
    }
}

Instead of cancelling the thread, it just seems to interrupt it, which causes Foo to continue its execution. Sorry for the verbosity, but I wanted to give you guys a clear picture. Any suggestions?

mre
  • 43,520
  • 33
  • 120
  • 170

2 Answers2

1

Unless the task stops when interrupted, the flag will just be set and remain set until the task ends or decides to stop.

Possible duplicate of http://www.google.co.uk/search?q=how+do+I+stop+a+thread+in+Java 28,000,000 results.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • @Peter: Why isn't `getTask().cancel(true)` stopping the thread? It only seems to interrupt it, which isn't clear from the API. – mre Apr 28 '11 at 14:28
  • @sthupashmaht There's no clean way to cancel thread as thread can hold locks. – Victor Sorokin Apr 28 '11 at 14:29
  • The javadoc says `mayInterruptIfRunning - true if the thread executing this task should be interrupted;` It doesn't even guarentee to interrupt the thread. (And it won't if it is not running) – Peter Lawrey Apr 28 '11 at 14:30
  • @Peter: I have a feeling this isn't the best way to approach this problem then. Any suggestions? – mre Apr 28 '11 at 14:31
  • @Victor Sorokin, Thread.stop() will kill a thread and release all locks correctly, but there is no simple way to do this without leaving the system in a potentially inconsistent state. – Peter Lawrey Apr 28 '11 at 14:31
  • @sthupahsmaht, Have your code check for Thread.currentThread().isInterrupted() periodically. Or the shorter Thread.interrupted() (read the javadoc on this before using it ;) – Peter Lawrey Apr 28 '11 at 14:32
1

AFAIK, threads don't support the notion of "cancelling" out of the box. You have to bake in the logic to "cancel" your specific tasks when your thread is interrupted. This is typically done by checking the interrupt status of the thread when running your task/job and exit out cleanly if the status has been set to true (which happens when you call interrupt).

A sample snippet which might help you out. Also read, shutting down threads cleanly.

Sanjay T. Sharma
  • 22,857
  • 4
  • 59
  • 71