2012-05-01 13 views
16

Ho recentemente ereditato una grande applicazione Java che non ha quasi nessuna sicurezza di thread. Quello su cui sto lavorando attualmente è ottenere che tutti i thread siano in grado di gestire correttamente l'interruzione invece di utilizzare il pessimo Thread.stop().Metodi che annullano il flag Thread.interrupt()

Parte del problema è stato che non conosco tutti i metodi richiamati che cancellano il flag di interrupt.

Attualmente mi sa che di seguito sarà chiaro il flag di interrupt:

Thread.interrupted() 
Thread.sleep(long) 
Thread.join() 
Thread.join(long) 
Object.wait() 
Object.wait(long) 

Che altro mi manca? Grazie

risposta

25

Parte del problema è stato che non conosco tutti i metodi richiamati che cancellano il flag di interrupt.

E 'importante chiarire che i seguenti metodi di cancellare il flag di interrupt semplicemente chiamandoli:

Thread.interrupted() 
Thread.isInterrupted(true) -- added to your list 

Per questo motivo Thread.currentThread().isInterrupted() dovrebbe essere sempre usato al posto.

I seguenti metodi saranno cancellare il flag interrotto da immediatamente gettando InterruptedException o se sono stati chiamati e poi il filo è stato interrotto o se il filo è stato già interrotto e poi sono stati chiamati (vedi codice JUnit sotto). Quindi non è il metodo che cancella la bandiera, l'eccezione fa.

Thread.sleep(long) 
Thread.join() 
Thread.join(long) 
Thread.join(int, long) – added to your list 
Object.wait() 
Object.wait(long) 
Object.wait(int, long) – added to your list 
BlockingQueue.put(...) – added to your list 
BlockingQueue.offer(...) – added to your list 
BlockingQueue.take(...) – added to your list 
BlockingQueue.poll(...) – added to your list 
Future.get(...) – added to your list 

Si noti che il modello corretta con qualsiasi codice che cattura InterruptedException è da ripristinare immediatamente interrompere il filo. Facciamo questo nel caso in cui gli altri si affidano al metodo thread.isInterrupted():

try { 
    ... 
} catch (InterruptedException e) { 
    // immediately re-interrupt the thread 
    Thread.currentThread().interrupt(); 
    // log the exception or [likely] quit the thread 
} 

codice JUnit che dimostra alcune di queste:

assertFalse(Thread.currentThread().isInterrupted()); 
// you can do this from another thread by saying: someThread.interrupt(); 
Thread.currentThread().interrupt(); 
// this method does _not_ clear the interrupt flag 
assertTrue(Thread.currentThread().isInterrupted()); 
// but this one _does_ and should probably not be used 
assertTrue(Thread.interrupted()); 
assertFalse(Thread.currentThread().isInterrupted()); 
Thread.currentThread().interrupt(); 
assertTrue(Thread.currentThread().isInterrupted()); 
try { 
    // this throws immediately because the thread is _already_ interrupted 
    Thread.sleep(1); 
    fail("will never get here"); 
} catch (InterruptedException e) { 
    // and when the InterruptedException is throw, it clears the interrupt 
    assertFalse(Thread.currentThread().isInterrupted()); 
    // we should re-interrupt the thread so other code can use interrupt status 
    Thread.currentThread().interrupt(); 
} 
assertTrue(Thread.currentThread().isInterrupted()); 
10

La convenzione comune è la seguente: qualsiasi metodo che genera InterruptedException (+ Thread.interrupted()) cancella il flag di interrupt.

Quindi, per rendere i thread interrompibili è necessario trovare tutti i punti in cui viene catturato lo InterruptedException senza doverlo ripetere o ripristinare il flag di interrupt. Poiché InterruptedException è un'eccezione controllata, non è difficile da eseguire.

+0

Questa è stata la prima passata alla base di codice che ho eseguito, tuttavia mi trovo di fronte a una situazione in cui i programmatori precedenti avrebbero rilevato un'eccezione generale anziché una interruptedException. – OverflowingStack

1

Ecco un esempio di super divertente:

ch.qos.logback .core.AsyncAppenderBase precedente alla versione 1.1.4 cattura e inghiotte InterruptedException senza reimpostare il flag sul thread.

Quindi, se si utilizza qualsiasi cosa instradata a questo registratore (come slf4j), verrà silenziosamente consumato lo stato di interruzione del thread. "Cos, voglio dire, chi non controlla lo stato di interruzione del thread prima e dopo ogni possibile operazione di registro?

Problemi correlati