Hoe stop je een java-thread op een elegante manier?

Ik heb een thread geschreven, het kost te veel tijd om het uit te voeren en het lijkt erop dat het nog niet helemaal klaar is. Ik wil de draad gracieus stoppen. Hulp?


Antwoord 1, autoriteit 100%

De goedemanier om dit te doen is om de run()van de thread te laten bewaken door een booleanvariabele en deze in te stellen op truevan buitenaf wanneer je het wilt stoppen, zoiets als:

class MyThread extends Thread
{
  volatile boolean finished = false;
  public void stopMe()
  {
    finished = true;
  }
  public void run()
  {
    while (!finished)
    {
      //do dirty work
    }
  }
}

Er was eens een stop()methode, maar zoals de documentatie aangeeft

Deze methode is inherent onveilig. Het stoppen van een thread met Thread.stop zorgt ervoor dat alle monitoren worden ontgrendeld die het heeft vergrendeld (als een natuurlijk gevolg van de niet-aangevinkte ThreadDeath-uitzondering die zich door de stapel verspreidt). Als een van de objecten die eerder door deze monitoren werden beschermd zich in een inconsistente staat bevond, worden de beschadigde objecten zichtbaar voor andere threads, wat mogelijk kan resulteren in willekeurig gedrag.

Daarom zou je een bewaker moeten hebben..


Antwoord 2, autoriteit 21%

Het slechte van het gebruik van een vlag om je thread te stoppen, is dat als de thread wacht of slaapt, je moet wachten tot hij klaar is met wachten/slapen. Als u de interrupt-methode op de thread aanroept, wordt de wacht- of slaapoproep beëindigd met een InterruptedException.

(Een tweede nadeel van de vlagbenadering is dat de meeste niet-triviale code bibliotheken zoals java.util.concurrent zal gebruiken, waarbij de klassen specifiek zijn ontworpen om onderbrekingen te gebruiken om te annuleren. Proberen de handgerolde vlag te gebruiken in een taak die wordt doorgegeven aan een uitvoerder zal lastig zijn.)

Het aanroepen van interrupt() stelt ook een onderbroken eigenschap in die u kunt gebruiken als een vlag om te controleren of u wilt stoppen (in het geval dat de thread niet wacht of slaapt).

Je kunt de run-methode van de thread zo schrijven dat de InterruptedException wordt opgevangen buiten de luslogica die de thread aan het doen is, of je kunt de uitzondering in de lus vangen en dicht bij de aanroep die de uitzondering genereert, waarbij de interruptvlag binnen de vangst wordt geplaatst blok voor de InterruptedException, zodat de thread niet uit het oog verliest dat deze is onderbroken. De onderbroken thread kan nog steeds de controle behouden en de verwerking op zijn eigen voorwaarden voltooien.

Stel dat ik een werkthread wil schrijven die in stappen werkt, waar om de een of andere reden een slaapstand in het midden is, en ik niet wil dat ik de slaapstand stop om de verwerking te stoppen zonder het resterende werk voor die stap te doen, Ik wil alleen dat het stopt als het tussen twee stappen in is:

class MyThread extends Thread
{
    public void run()
    {
        while (!Thread.currentThread().isInterrupted())
        {
            doFirstPartOfIncrement();
            try {
                Thread.sleep(10000L);
            } catch (InterruptedException e) {
                // restore interrupt flag
                Thread.currentThread().interrupt();
            }
            doSecondPartOfIncrement();
        }
    }
}

Hier is een antwoord op een vergelijkbare vraag, inclusief voorbeeldcode.


Antwoord 3, autoriteit 14%

Je moet Thread niet van een andere verwijderen. Het wordt beschouwd als een vrij slechte gewoonte. Er zijn echter veel manieren. U kunt de instructie returngebruiken uit de run-methode van thread.
Of u kunt controleren of de thread al is onderbroken en dan wordt het werk geannuleerd. F.e. :

while (!isInterrupted()) { 
  // doStuff
}

Antwoord 4, autoriteit 7%

Maak ergens een vluchtige boolean stop. Doe dan regelmatig in de code die in de thread wordt uitgevoerd

if (stop) // end gracefully by breaking out of loop or whatever

Als u de thread wilt stoppen, stelt u stopin op true.

Ik denk dat je het op deze manier handmatig moet doen. Immers, alleen de code die in de thread wordt uitgevoerd, heeft enig idee wat wel en niet sierlijk is.


Antwoord 5, autoriteit 4%

Je moet een stop-bericht naar de Thread sturen en de Thread zelf moet actie ondernemen als het bericht is ontvangen. Dit is vrij eenvoudig, als de langlopende actie binnen de lus is:

public class StoppableThread extends Thread {
   private volatile boolean stop = false;
   public void stopGracefully() {
     stop = true;
   }
   public void run() {
     boolean finished = false;
     while (!stop && !finished) {
       // long running action - finished will be true once work is done
     }
   }
}

Antwoord 6

Als een thread zichzelf wil laten stoppen, lijkt niemand het (mis)gebruiken van uitzondering te hebben genoemd:

abstract class SelfStoppingThread extends Thread {
    @Override
    public final void run() {
        try {
            doRun();
        } catch (final Stop stop) {
            //optional logging
        }
    }
    abstract void doRun();
    protected final void stopSelf() {
        throw new Stop();
    }
    private static final class Stop extends RuntimeException {};
}

Een subklasse hoeft alleen maar doRun() te overschrijven zoals je zou doen met een Thread, en stopSelf() aan te roepen wanneer het voelt alsof het wil stoppen. IMO voelt het schoner aan dan het gebruik van een vlag in een while-lus.

Other episodes