2013-05-10 15 views
15

Mam LockManager, który zarządza blokadami kilku wątków. Czasami nici są złymi chłopcami i muszę je zabić i poprosić LockManagera o zwolnienie wszystkich zamków. Jednakże, ponieważ używam ReentrantLock w java jest to niemożliwe, nie mogę odblokować blokady posiadanej przez inny wątek.Blokada odblokowująca należąca do innego wątku java

Jestem zmuszony korzystać z Zamków (nie można używać semaforów, jest to punkt pracy domowej). Czy istnieje implementacja Java Lock, która pozwala mi odblokować blokady będące własnością innych wątków?

Dotychczas opcji I uważane są:

  • ponownego wdrażania ReentrantLock w sposób, który pozwala mi na to
  • Dodać jakieś mapowanie między semafory i ReentrantLocks

Extra zrobić Źródła, które mogą Ci się przydać:

Odpowiedz

7

Czy wolno używać własnego Lock? Oto klasa, która jest całkowicie proxy dla Lock, ale kiedy mówi się, aby wymusić odblokowanie, po prostu zastępuje blokadę, która jest proxy z nową. To powinno mieć pożądany skutek. Niestety nadal nie dotyczy to zamków, które pozostają w zawieszeniu, ale teraz staje się problemem kogoś innego. Twoje zamki są teraz magicznie odblokowane.

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

Tak, mogę używać mój własny zamek i dziękuję! Mój partner i ja faktycznie zaimplementowaliśmy naszą własną wersję symulującą interfejs LOCK za pomocą semaforów –

+0

Nie widzę jak ta implementacja wa wątki kes, które czekają na poprzednią blokadę ... –

+0

@GerardoLastra - * Niestety nadal nie radzi sobie z blokadami, które pozostały zwisające, ale teraz staje się problemem kogoś innego. * – OldCurmudgeon

10

pan odkrył jeden z głównych powodów, dlaczego wspólne mądrość mówi: Nie zabijaj tematy!

Blokady to tylko jeden z potencjalnych wycieków zasobów, które mogą się zdarzyć, gdy siłą zabijesz wątek. Rozważ otwarte pliki i gniazda, itp.

Należy również wziąć pod uwagę, że jeśli udało się odblokować blokadę, był powód, dla którego blokada została zablokowana. Na przykład wątek mógł częściowo zaktualizować strukturę danych, a umożliwienie dostępu do tej struktury z innego wątku prawdopodobnie spowoduje dziwne i zdumiewające awarie programu, które są trudne, jeśli nie niemożliwe do debugowania.

Najlepszym sposobem na poradzenie sobie z tą sytuacją jest poprosić wątek, aby odszedł. Dodaj metodę "stop()" do obiektu skojarzonego z wątkiem (masz obiekt dla każdego wątku, prawda?), Który ustawia flagę i ma wątek sprawdzania tej flagi regularnie i kończy działanie, jeśli jest ustawiony .

Jeśli twoje wątki źle się trzymają w sposób, który uniemożliwia im sprawdzenie flagi zatrzymania, poprawne jest naprawienie kodu, aby nie działał nieprawidłowo.

-2

Dlaczego nie można po prostu zawinąć kod swojego wątku wokół następujących czynności:

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

Następnie, gdy kończy wątek (albo normalnie wykończeniowych, lub rzucając wyjątek od swojego „zabić”) , zwolni blokadę.

To jest rzeczywiście droga Oracle zaleca stosowanie ReentrantLock: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html

+0

To nie rozwiązuje mojego problemu.Widzisz, mam kilka wątków uruchomionych, a rozwiązaniem jest, gdy możesz uzyskać blokadę wiedząc, do kogo należy. Prawdziwy problem polega na tym, że mój LockManager musi wywoływać "unlock" na blokadach będących własnością innych wątków = ( –

+0

Wygląda na to, że masz problem z twoją ogólną architekturą używającą tego LockManagera, podczas programowania współbieżnego powinieneś mieć "współpracę" mindset: twoje wątki działają razem, a nie przeciwko sobie.Możesz użyć dokładnie tego samego podejścia, zastępując lock.unalock() z czymś takim jak lockManager.release (lock), jeśli chcesz, aby LockManager zadzwonił do odblokowania, lub możesz sprawić, że twój LockManager zapewni Wątek roboczy z jakimś obiektem, który zostanie użyty do powiadomienia o zakończeniu wątku, i użyje go dokładnie tak, jak pokazano powyżej (np. spróbuj {...} w końcu {finishedFlag.set();}. –

Powiązane problemy