Как я могу прервать синхронизированный оператор в Java? - PullRequest
7 голосов
/ 21 февраля 2010

У меня есть два потока, которые хотят синхронизировать один и тот же объект. Thead A должен иметь возможность прерывать поток B, если определенное условие было выполнено. Вот некоторый псевдокод того, что два потока делают / должны делать.

A:

public void run()
{
    while(true)
    {
        //Do stuff
        synchronized(shared)
        {
            //Do more stuff
            if(condition)
            {
                B.interrupt();
            }
        }
    }
}

B

public void run()
{
    while(true)
    {
        try
        {
            //Do stuff
            synchronized(shared)
            {
            //Do more stuff
            }
        }
        catch(InterruptedException e)
        {
            continue;
        }
    }
}

Вот ситуация, которую я не могу разрешить:

  • Тема A захватывает общий ресурс и делает что-то еще.
  • Тем временем поток B достигает синхронизированного блока и ожидает, пока A освободит свой общий ресурс.
  • Поток A, делая что-то, понял, что Поток B не должен иметь общего ресурса, и пытается прервать Поток B. Но нить B уже превзошла точки, в которые можно было бы бросить InterruptedException.

У меня вопрос, есть ли способ прервать поток, пока он ожидает, чтобы быть synchronized на чем-то?

Ответы [ 3 ]

5 голосов
/ 21 февраля 2010

Для такого рода вещей вы должны использовать классы в java.util.concurrent.locks - у них гораздо больше возможностей, включая прерываемые блокировки.

Редактировать: Если вы не можете использовать эти классы, посмотрите на ответ jkff - ваши требования могут быть удовлетворены с помощью механизма wait() / notify(), но легко вводить тонкие ошибки.

2 голосов
/ 21 февраля 2010

Действительно, вы должны использовать блокировки или реализовывать свои вещи с помощью методов Object.wait(), Object.notify() и Object.notifyAll() (блокировки фактически реализуются с их помощью). Не забудьте обработать так называемые «ложные пробуждения» (wait() может возвращаться, даже если никто не вызвал notify() или notifyAll(), поэтому его всегда следует вызывать в цикле, который проверяет, что условие, которое вы ждете доволен).

1 голос
/ 21 февраля 2010

Нет, но <a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantLock.html#lockInterruptibly()" rel="nofollow noreferrer">ReentrantLock.lockInterruptibly()</a> ведет себя аналогично примитивной инструкции monitorenter и может быть прервано.

...