Chi chiama il metodo Java Thread interrupt () se non lo sono?


87

Ho letto e riletto Java Concurrency in Practice, ho letto diversi thread qui sull'argomento, ho letto l'articolo IBM Dealing with InterructedException eppure c'è qualcosa che semplicemente non capisco che penso possa essere rotto in due domande:

  1. Se non interrompo mai altri thread da solo, cosa può attivare un'eccezione interrotta ?

  2. Se non interrompo mai altri thread da solo usando interrupt () (diciamo perché sto usando altri mezzi per cancellare i miei thread di lavoro, come le pillole velenose e il ciclo di stile while (! Cancellato) [come entrambi spiegati in JCIP]), cosa cosa significa allora un'eccezione interrotta ? Cosa dovrei fare dopo averne catturato uno? Chiudere la mia app?

Risposte:


50

Il meccanismo di interruzione del thread è il modo migliore per ottenere un thread (cooperante) per rispondere a una richiesta per interrompere ciò che sta facendo. Qualsiasi thread (incluso il thread stesso credo) potrebbe chiamare interrupt()un thread.

In pratica, i normali casi d'uso interrupt()coinvolgono un qualche tipo di framework o manager che dice ad alcuni thread di lavoro di interrompere ciò che stanno facendo. Se il thread di lavoro è "consapevole delle interruzioni", noterà che è stato interrotto tramite un'eccezione o controllando periodicamente il suo flag interrotto. Notando che è stato interrotto, un thread ben educato abbandonerebbe ciò che sta facendo e finirebbe a se stesso.

Supponendo il caso d'uso di cui sopra, è probabile che il codice venga interrotto se viene eseguito all'interno di un framework Java o da un thread di lavoro. E quando viene interrotto, il codice deve abbandonare ciò che sta facendo e terminare se stesso con i mezzi più appropriati. A seconda di come è stato chiamato il codice, ciò potrebbe essere fatto restituendo o generando un'eccezione appropriata. Ma probabilmente non dovrebbe chiamare System.exit(). (La tua applicazione non sa necessariamente perché è stata interrotta e di certo non sa se ci sono altri thread che devono essere interrotti dal framework.)

D'altra parte, se il tuo codice non è progettato per essere eseguito sotto il controllo di qualche framework, potresti sostenere che InterruptedExceptionè un'eccezione inaspettata; cioè un bug. In tal caso, dovresti trattare l'eccezione come faresti con gli altri bug; ad esempio, racchiudilo in un'eccezione non controllata e catturalo e registralo nello stesso punto in cui gestisci altre eccezioni non controllate impreviste. (In alternativa, l'applicazione potrebbe semplicemente ignorare l'interruzione e continuare a fare ciò che stava facendo.)


1) Se non interrompo mai altri thread da solo, cosa può attivare un'eccezione interrotta?

Un esempio è se i tuoi Runnableoggetti vengono eseguiti utilizzando un ExecutorServicee shutdownNow()viene chiamato sul servizio. E in teoria, qualsiasi pool di thread di terze parti o framework di gestione dei thread potrebbe legittimamente fare qualcosa di simile.

2) Se non interrompo mai personalmente altri thread usando interrupt () ... cosa significa InterruptedExceptionallora? Cosa dovrei fare dopo averne catturato uno? Chiudere la mia app?

È necessario analizzare la base di codice per capire cosa sta effettuando le interrupt()chiamate e perché. Dopo averlo capito, puoi capire cosa >> la tua << parte dell'app deve fare.

Fino a quando non saprai perché InterruptedExceptionviene lanciato, ti consiglio di trattarlo come un errore difficile; es. stampa uno stacktrace nel file di registro e chiudi l'app. (Ovviamente, non è sempre la risposta giusta ... ma il punto è che questo è "un bug", e deve essere portato all'attenzione dello sviluppatore / manutentore.)

3) Come faccio a sapere chi / cosa sta chiamando interrupt()?

Non c'è una buona risposta a questo. Il meglio che posso suggerire è di impostare un punto di interruzione sul Thread.interrupt()e guardare lo stack di chiamate.


12

Se decidi di integrare il tuo codice con altre librerie, queste possono richiamare interrupt()il tuo codice. ad esempio, se in futuro decidi di eseguire il codice all'interno di un ExecutorService , ciò potrebbe forzare l'arresto tramite interrupt().

Per dirla brevemente, prenderei in considerazione non solo dove è in esecuzione il codice ora , ma in quale contesto potrebbe essere eseguito in futuro. es. lo metti in una libreria? Un container ? Come lo useranno le altre persone? Lo riutilizzerai?


Pensavo che solo shutdownNow chiamasse il metodo interrupt (). È vero anche per l'arresto?
Harinder

9

Come altri hanno sottolineato, l'interruzione di un thread (in realtà, l'interruzione di una chiamata di blocco) viene solitamente utilizzata allo scopo di uscire in modo pulito o annullare un'attività in corso.

Tuttavia, non dovresti considerare un InterruptedExceptioncomando da solo come un "comando di chiusura". Invece, dovresti pensare agli interrupt come a un mezzo per controllare lo stato di esecuzione dei thread, in modo molto simile a come Object.notify()fa. Allo stesso modo in cui controlleresti lo stato corrente dopo esserti svegliato da una chiamata a Object.wait()(non presumi che il risveglio significhi che la tua condizione di attesa è stata soddisfatta), dopo essere stato spinto con un'interruzione dovresti controllare perché sei stato interrotto . Di solito c'è un modo per farlo. Ad esempio, java.util.concurrent.FutureTaskha un isCancelled()metodo.

Esempio di codice:

public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}

3

Il problema con la domanda è "io". "I" di solito si riferisce a una singola istanza di una classe. Con questo intendo dire che qualsiasi particolare pezzo di codice (classe) di basso livello non dovrebbe fare affidamento sull'implementazione dell'intero sistema. Detto questo, devi prendere alcune decisioni "architettoniche" (come la piattaforma su cui eseguire).

Eventuali interruzioni impreviste provenienti dal JRE sono attività annullate java.util.concurrente chiusura di applet.

La gestione degli interrupt di thread è solitamente scritta in modo errato. Pertanto, suggerisco la decisione architettonica per evitare di causare interruzioni ove possibile. Tuttavia, gli interrupt di gestione del codice dovrebbero sempre essere scritti correttamente. Non posso togliere le interruzioni dalla piattaforma ora.


Ciao Tom, ricordo il tuo nome da cljp;) Ebbene, precisamente: non ho mai dovuto lanciare interrupt () da solo ... A meno che non riceva un'eccezione interrotta e devo riaffermare lo stato di interruzione ma questo non è ancora al 100% chiaro per me. Sono nuovo qui e sorpreso dal numero di voti positivi e risposte / commenti (sia quelli corretti che quelli sbagliati): ovviamente è un argomento non banale o, almeno, di solito non ben spiegato. Detto questo grazie a tutti i post che sto iniziando a ottenere un quadro più chiaro di quello che sta succedendo :)
SyntaxT3rr0r

3

Puoi apprenderlo creando la tua classe thread ( extending java.lang.Thread) e sovrascrivendo il interrupt()metodo, in cui registri lo stacktrace, diciamo, in un campo String, e poi trasferisci a super.interrupt ().

public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}

1

Come già accennato, un'altra libreria può interrompere i tuoi thread. Anche se la libreria non ha accesso esplicito ai thread dal codice, può comunque ottenere l'elenco dei thread in esecuzione e interromperli in questo modo con il metodo seguente .


1

Penso di capire perché sei un po 'confuso riguardo all'interruzione. Si prega di considerare le mie risposte in linea:

Se non interrompo mai altri thread da solo, cosa può attivare un'eccezione interrotta ?

Innanzitutto puoi interrompere altri thread; So che in JCiP si dice che non dovresti mai interrompere i thread che non possiedi; tuttavia, questa affermazione deve essere correttamente compresa. Ciò significa che il codice che potrebbe essere in esecuzione in qualsiasi thread arbitrario non dovrebbe gestire l'interruzione perché poiché non è il proprietario del thread non ha la minima idea della sua politica di interruzione. Quindi puoi richiedere l'interruzione su altri thread, ma lasciare che il suo proprietario esegua l'azione di interruzione; ha la politica di interruzione incapsulata al suo interno, non il codice dell'attività; almeno sii cortese a impostare la bandiera dell'interruzione!

Ci sono molti modi per cui potrebbero esserci ancora interruzioni, potrebbero esserci timeout, interruzioni JVM ecc.

Se non interrompo mai altri thread da solo usando interrupt () (diciamo perché sto usando altri mezzi per cancellare i miei thread di lavoro, come le pillole velenose e il ciclo di stile while (! Cancellato) [come entrambi spiegati in JCIP]), cosa cosa significa allora un'eccezione interrotta? Cosa dovrei fare dopo averne catturato uno? Chiudere la mia app?

Devi stare molto attento qui; se possiedi il thread che ha generato InterruptException (IE), allora sai cosa fare dopo averlo catturato, dì che potresti chiudere la tua app / servizio o potresti sostituire questo thread ucciso con uno nuovo! Tuttavia, se non si possiede il thread, dopo aver catturato IE, rilanciarlo più in alto nello stack di chiamate o dopo aver fatto qualcosa (potrebbe essere loggato), ripristinare lo stato interrotto in modo che il codice che possiede questo thread, quando il controllo lo raggiunge, possa apprendere che il thread è stato interrotto e quindi intraprendere azioni come farà poiché solo lui conosce la politica di interruzione.

Spero che questo abbia aiutato.


0

Il InterruptedExceptiondice che una routine può essere interrotto, ma non necessariamente che sarà.

Se non ti aspetti l'interruzione, dovresti trattarla come faresti con qualsiasi altra eccezione imprevista. Se si trova in una sezione critica in cui un'eccezione imprevista potrebbe avere conseguenze atroci, potrebbe essere meglio provare a ripulire le risorse e spegnerlo con garbo (perché ottenere l'interrupt segnala che viene utilizzata la tua applicazione ben progettata che non si basa sugli interrupt in un certo senso non è stato progettato, quindi deve esserci qualcosa che non va). In alternativa, se il codice in questione è qualcosa di non critico o banale, potresti voler ignorare (o registrare) l'interruzione e andare avanti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.