2013-05-10 11 views
15

Ho un LockManager che gestisce i blocchi di più thread. A volte i thread sono cattivi ragazzi, e devo ucciderli e chiedo al LockManager di rilasciare tutti i loro lucchetti. Tuttavia, dal momento che utilizzo ReentrantLock in java è impossibile, non riesco a sbloccare un blocco di proprietà di un altro thread.Unlocking lock di proprietà di un altro thread java

Sono costretto a utilizzare i blocchi (non è possibile utilizzare i semafori, è il punto dei compiti). Esiste un'implementazione di Java Lock che mi consenta di sbloccare blocchi di proprietà di altri thread?

Finora le opzioni che ho considerate sono:

  • ri-attuazione ReentrantLock in un modo che mi permette di fare questo
  • fare una sorta di mappatura tra semafori e ReentrantLocks

Extra Fonti che potresti trovare utili:

risposta

7

Vuoi essere consentito di utilizzare il proprio Lock? Ecco una classe che esegue il proxy completo su Lock ma, quando viene detto di forzare lo sblocco, sostituisce semplicemente il blocco che sta trasmettendo con uno nuovo. Questo dovrebbe avere l'effetto desiderato. Tristemente non si occupa ancora delle serrature che vengono lasciate penzolare ma che ora diventa il problema di qualcun altro. Le tue serrature ora sono sbloccate magicamente.

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

Sì, sono autorizzato ad usare il mio lucchetto e grazie! Il mio compagno e io abbiamo effettivamente implementato la nostra versione che simula l'interfaccia LOCK usando i semafori. –

+0

Non riesco a vedere come questa implementazione kes thread che stanno aspettando sul lock precedente ... –

+0

@GerardoLastra - * Purtroppo non si occupa ancora delle serrature che vengono lasciate penzolare ma che ora diventa il problema di qualcun altro. * – OldCurmudgeon

10

hai scoperto una delle principali ragioni per cui la saggezza comune dice: Non uccidere le discussioni!

I blocchi sono solo una delle potenziali perdite di risorse che possono verificarsi se si uccide forzatamente un thread. Prendi in considerazione file aperti e socket, ecc.

Considerare anche che se si è riusciti a sbloccare il blocco, c'era un motivo per cui il blocco era bloccato in primo luogo. Ad esempio, il thread potrebbe aver parzialmente aggiornato una struttura dati e consentire l'accesso a quella struttura da un altro thread può causare errori di programma strani e meravigliosi che sono difficili se non impossibili da eseguire il debug.

Il modo migliore per gestire questa situazione è chiedere al thread di andare via. Aggiungi un metodo "stop()" all'oggetto associato al thread (hai un oggetto per ogni thread, non è vero?) Che imposta un flag, e verifica che il thread controlli questo flag regolarmente ed esca se è impostato .

Se i thread si comportano male in un modo che impedisce loro di controllare il flag di stop, l'approccio corretto è quello di correggere il codice in modo che non si comportino male.

-2

Perché non è sufficiente avvolgere il codice del vostro filo attorno alla seguente:

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

Poi, quando i thread termina (o con finitura normalmente, o di un'eccezione dal "uccidere") , rilascerà il blocco.

Questo è in realtà il modo in cui Oracle consiglia di utilizzare ReentrantLock: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html

+0

Questo non risolve il mio problema.Vedete, ho diversi thread in esecuzione e quella soluzione è quando potete ottenere il blocco sapendo a chi appartiene. Il vero problema è che il mio LockManager deve chiamare "unlock" sui blocchi di proprietà di altri thread = ( –

+0

Sembra che tu abbia un problema con la tua architettura generale usando quella cosa di LockManager. Quando fai una programmazione concorrente, dovresti avere una "collaborazione" mindset: i tuoi thread lavorano insieme, non l'uno contro l'altro.Puoi usare lo stesso identico approccio sostituendo lock.unalock() con qualcosa come lockManager.release (lock) se vuoi che LockManager invii lo sblocco, o potresti rendere il tuo LockManager fornire il tuo thread di lavoro con qualche oggetto che sarebbe stato usato per notificare il thread è finito e usarlo esattamente come mostrato sopra (cioè, prova {...} finally {finishedFlag.set();}. –

Problemi correlati