2010-07-07 29 views

Respuesta

66

El buena manera de hacerlo es tener la run() de la rosca vigilado por una variable boolean y ponerlo a true desde el exterior cuando se desea detenerlo, algo así como:

class MyThread extends Thread 
{ 
    volatile boolean finished = false; 

    public void stopMe() 
    { 
    finished = true; 
    } 

    public void run() 
    { 
    while (!finished) 
    { 
     //do dirty work 
    } 
    } 
} 

Érase una vez un método stop() existía pero como la documentación indica

Este método es inherentemente inseguro. Detener un hilo con Thread.stop hace que desbloquee todos los monitores que ha bloqueado (como consecuencia natural de la excepción ThreadDeath no verificada que se propaga por la pila). Si alguno de los objetos previamente protegidos por estos monitores se encontraba en un estado incoherente, los objetos dañados se vuelven visibles para otros hilos, lo que puede generar un comportamiento arbitrario.

Es por eso que usted debe tener un guardia ..

+2

Vea el comentario de Jon Skeet a la respuesta de Bart, se aplica también al suyo. –

+0

Si el cambio "terminado" cambia mientras está haciendo su trabajo sucio, el hilo no terminará, entonces tiene que hacer una comprobación periódica, por ejemplo, con un ciclo de suspensión (sleep), algo que no se recomienda y le da un mal rendimiento, ¿es realmente este un buen enfoque? –

+0

estamos hablando de dejar un hilo con gracia. Obligar a un hilo a dejar de fumar en medio de su trabajo sucio no es una manera elegante de hacerlo. Siempre debe esperar para la próxima iteración a menos que usted tiene una razón específica para interrumpirlo .. – Jack

4

Haz un booleano volátil stop en alguna parte. Luego, en el código que se ejecuta en el hilo, hacer regularmente

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

Para detener el hilo, fijado a stoptrue.

Creo que debe hacerlo manualmente de esta manera. Después de todo, solo el código que se ejecuta en el hilo tiene alguna idea de lo que es y no es gracioso.

+21

Tenga en cuenta que sea necesario utilizar el bloqueo o hacer que el campo volátil para asegurarse de que el hilo de la lectura ve cambios con respecto al hilo de la escritura. –

+0

@Jon Skeet: Sí, eso sería mejor. Por curiosidad, ¿cuánto tiempo se demoraría aproximadamente si el campo no es volátil? –

+5

@Bart: en práctica, probablemente no mucho. En teoría, para siempre. –

10

Usted no debe matar a rosca de otro. Se considera un hábito bastante malo. Sin embargo, hay muchas formas. Puede usar la instrucción return desde el método run del hilo. O puede verificar si el hilo ya ha sido interrumpido y luego cancelará su trabajo. F.e. :

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

El método de ejecución es nulo, no puede devolver nada. –

+3

puede usar la declaración de devolución vacía con el tipo de devolución nula, el método terminará – Xorty

+0

esto es similar a la primera respuesta, excepto que está utilizando return en lugar de simplemente dejar que el método run() salga. Y sí, solo puede usar return; y que saldrá de un método nulo – Richard

3

Es necesario enviar un mensaje de detención al hilo y el hilo en sí tiene que tomar medidas si el mensaje ha sido recibido. Esto es bastante fácil, si la acción de larga duración está dentro del bucle:

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 
    } 
    } 
} 
+1

Como Jon Skeet comentó en mi respuesta, parada debe ser volátil –

+0

I editado mi respuesta, pero voy a ir a buscar a cabo, por lo que se aplica aquí - en su respuesta, pensé, tenía que ser volátil sólo porque usted no mencionó una método y parecía que el campo 'stop' tenía que ser accedido directamente. –

+1

me he preguntado acerca de la palabra clave volátil antes y (sin tratar de hacer publicidad de mi propia pregunta :)), aquí hay algunas respuestas en él: http://stackoverflow.com/questions/106591/do-you-ever- use-the-volátil-keyword-in-java – Richard

12

Lo malo de usar una bandera para detener el hilo es que si el hilo está esperando o dormir entonces usted tiene que esperar a que se terminar esperando/durmiendo. Si llama al método de interrupción en el subproceso, eso hará que la llamada de espera o de espera se cierre con una excepción interrumpida.

La interrupción de llamada() también establece una propiedad interrumpida que puede usar como indicador para comprobar si se cierra (en caso de que el hilo no esté esperando o durmiendo).

Puede escribir método run del hilo para que la InterruptedException es atrapado fuera de cualquier bucle lógica de la rosca está haciendo, o se puede detectar la excepción dentro del bucle y cerca de la llamada lanzar la excepción, estableciendo el indicador de interrupción dentro de la catch block para InterruptedException para que el hilo no pierda de vista el hecho de que fue interrumpido. El hilo interrumpido aún puede mantener el control y finalizar el procesamiento en sus propios términos.

Digamos que quiero escribir un subproceso de trabajo que funciona en incrementos, donde hay una pausa en el medio por alguna razón, y no quiero dejar el reposo para que el proceso se cierre sin hacer el trabajo restante para ese incremento , sólo lo quieren dejar de fumar si está en el medio incrementos:

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(); 
     } 
    } 
} 

Here is an answer to a similar question, including example code.

1

para un hilo para detener la misma, nadie parece haber mencionado (mal) uso de excepción:

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 {}; 

} 

Una subclase sólo tiene que anular doRun() normalmente como lo haría con un hilo, y llamar a stopSelf() cada vez que se siente como que quiere parar. OMI se siente más limpio que usar una bandera en un ciclo while.

Cuestiones relacionadas