2013-05-10 3 views
15

У меня есть LockManager, который управляет замками нескольких потоков. Иногда потоки - плохие парни, и я должен их убить и попросить LockManager выпустить все свои блокировки. Однако, поскольку я использую ReentrantLock в java, это невозможно, я не могу разблокировать блокировку, принадлежащую другому потоку.Блокировка блокировки, принадлежащая другой теме java

Я вынужден использовать Замки (не могу использовать семафоры, это точка домашней работы). Есть ли какая-либо реализация Java Lock, которая позволяет мне разблокировать блокировки, принадлежащие другим потокам?

До сих пор варианты я Рассматриваемый:

  • повторного внедрение ReentrantLock таким образом, что позволяет мне сделать это
  • сделать какое-то отображение между семафорами и ReentrantLocks

Extra Источники, которые могут оказаться полезными:

ответ

7

ли вы иметь возможность использовать свой собственный Lock? Вот класс, который полностью проксирует Lock, но когда ему говорят, чтобы заставить разблокировать, он просто заменяет блокировку, которую он проксирует с помощью новой. Это должно иметь эффект, который вы хотите. К сожалению, это все еще не касается замков, которые остаются свисающими, но теперь это становится чьей-то проблемой. Теперь ваши замки волшебным образом разблокированы.

static class LockProxy<L extends Lock> implements Lock { 

    // The actual lock. 
    private volatile Lock lock; 

    public LockProxy(L lock) { 
     // Trap the lock we are proxying. 
     this.lock = lock; 
    } 

    @Override 
    public void lock() { 
     // Proxy it. 
     lock.lock(); 
    } 

    @Override 
    public void lockInterruptibly() throws InterruptedException { 
     // Proxy it. 
     lock.lockInterruptibly(); 
    } 

    @Override 
    public boolean tryLock() { 
     // Proxy it. 
     return lock.tryLock(); 
    } 

    @Override 
    public boolean tryLock(long l, TimeUnit tu) throws InterruptedException { 
     // Proxy it. 
     return lock.tryLock(l, tu); 
    } 

    @Override 
    public void unlock() { 
     // Proxy it. 
     lock.unlock(); 
    } 

    @Override 
    public Condition newCondition() { 
     // Proxy it. 
     return lock.newCondition(); 
    } 

    // Extra functionality to unlock from any thread. 
    public void forceUnlock() { 
     // Actually just replace the perhaps locked lock with a new one. 
     // Kinda like a clone. I expect a neater way is around somewhere. 
     if (lock instanceof ReentrantLock) { 
      lock = new ReentrantLock(); 
     } else { 
      throw new UnsupportedOperationException(
       "Cannot force unlock of lock type " 
        + lock.getClass().getSimpleName()); 
     } 
    } 
} 
+0

Да, мне разрешено использовать мой собственный замок и спасибо! Я и сам на самом деле реализовали нашу собственную версию, которая имитирует интерфейс LOCK с помощью Семафоров. –

+0

Я не вижу, как эта реализация wa kes, которые ждут предыдущего замка ... –

+0

@GerardoLastra - * К сожалению, он все еще не имеет дело с замками, которые остаются болтающимися, но теперь это становится чьей-то проблемой. * – OldCurmudgeon

10

Вы обнаружили основную причину, почему здравый смысл говорит: Не убивайте темы!

Замки являются лишь одним из потенциальных утечек ресурсов, которые могут произойти, если вы принудительно уничтожаете поток. Рассмотрите открытые файлы и розетки и т. Д.

Также считайте, что если вам удалось разблокировать замок, была причина, по которой замок был заблокирован в первую очередь. Например, поток может частично обновить структуру данных и разрешить доступ к этой структуре из другого потока, вероятно, вызовет странные и чудесные сбои программ, которые трудно, если не невозможно, отлаживать.

Лучший способ справиться с этой ситуацией - попросить поток уйти. Добавьте метод «stop()» к объекту, связанному с потоком (у вас есть объект для каждого потока, не так ли?), Который устанавливает флаг и регулярно проверяет этот флажок и выходит, если он установлен ,

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

-2

Почему вы не просто обернуть код вашего потока вокруг следующего:

ReentrantLock lock = ... obtain your lock somehow ... 
lock.lock(); 
try { 
    ... the "bad boy" code here ... 
} finally { 
    lock.unlock(); 
} 

Затем, когда ваша нить заканчивается (либо нормально отделкой, или путем выбрасывания исключения из ваших «убить») , он освободит замок.

Это на самом деле так, как Oracle рекомендует использовать ReentrantLock: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html

+0

Это не решает мою проблему.Видите ли, у меня есть несколько потоков, и это решение - когда вы можете получить доступ к замку, которому он принадлежит. Реальная проблема заключается в том, что мой LockManager должен вызывать «разблокировать» блокировки, принадлежащие другим потокам = ( –

+0

Кажется, что у вас есть проблема с вашей общей архитектурой, используя эту функцию LockManager. При выполнении параллельного программирования у вас должно быть «сотрудничество», mindset: ваши потоки работают вместе, а не друг против друга. Вы можете использовать тот же подход, заменив lock.unalock() на что-то вроде lockManager.release (lock), если вы хотите, чтобы LockManager вызывал разблокировку, или вы могли бы сделать ваш LockManager ваш рабочий поток с каким-либо объектом, который будет использоваться для уведомления об этом потоке, будет завершен, и используйте его точно так, как показано выше (т. е. try {...} finally {finishedFlag.set();}. –