Future.отмена и повторные блокировки

#java #conditional-statements #future #reentrantlock

#java #условные операторы #будущее #повторная блокировка

Вопрос:

Сценарий

У меня есть этот класс, скажем Foo , единственной задачей которого является последовательное выполнение набора задач. Звучит просто, не так ли? Что ж, все эти задачи выполняются в их собственном отдельном потоке. Вместо простого вызова Thread.join() для каждой задачи для обеспечения последовательного выполнения, он использует ReentrantLock и Condition . Например,

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

После каждой задачи waitForNotification() вызывается и ожидает, скажем, другого класса, который Bar разбудит ее. Единственной задачей для Bar является обработка ответа, который информирует приложение о том, была ли задача выполнена или произошел сбой. При этом он выполнит одну из двух вещей:

  1. Полностью отмените поток (т. е. getTask().cancel )
  2. Разбудить поток (т.е. getCondition().signal )

Пункт 2 работает просто отлично, но пункт 1 не работает. Например,

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

Вместо отмены потока, кажется, что он просто прерывает его, что заставляет Foo продолжить его выполнение. Извините за многословие, но я хотел дать вам, ребята, ясную картину. Есть предложения?

Ответ №1:

AFAIK, потоки не поддерживают понятие «отмены» из коробки. Вы должны использовать логику для «отмены» ваших конкретных задач, когда ваш поток прерывается. Обычно это делается путем проверки состояния прерывания потока при выполнении вашей задачи / job и завершения работы, если для статуса установлено значение true (что происходит при вызове interrupt).

Пример фрагмента, который может вам помочь. Также прочитайте, завершая потоки чисто.

Ответ №2:

Если задача не останавливается при прерывании, флаг будет просто установлен и оставаться установленным до тех пор, пока задача не завершится или не решит остановиться.

Возможный дубликат http://www.google.co.uk/search ?вопрос= как мне остановить поток в Java 28 000 000 результатов.

Комментарии:

1. @Peter: Почему не getTask().cancel(true) останавливается поток? Кажется, что это только прерывает его, что неясно из API.

2. @sthupashmaht Нет чистого способа отменить поток, поскольку поток может содержать блокировки.

3. javadoc говорит, mayInterruptIfRunning - true if the thread executing this task should be interrupted; что даже не гарантирует прерывание потока. (И этого не произойдет, если он не запущен)

4. @Peter: Тогда у меня такое чувство, что это не лучший способ подойти к этой проблеме. Есть предложения?

5. @Виктор Сорокин, Thread.stop() завершит поток и правильно снимет все блокировки, но нет простого способа сделать это, не оставляя систему в потенциально несовместимом состоянии.