Matar hilos en Java

Un subproceso se destruye automáticamente cuando se completa el método run(). Pero podría ser necesario eliminar/detener un subproceso antes de que haya completado su ciclo de vida . Anteriormente, los métodos suspend() , resume() y stop() se usaban para gestionar la ejecución de subprocesos. Pero estos métodos quedaron obsoletos en Java 2 porque podrían provocar fallas en el sistema. Las formas modernas de suspender/detener un hilo son mediante el uso de una bandera booleana y el método Thread.interrupt().
 

  • Usando una bandera booleana: podemos definir una variable booleana que se usa para detener/matar hilos, diga ‘salir’. Siempre que queramos detener un hilo, la variable ‘salir’ se establecerá en verdadero. 

Java

// Java program to illustrate
// stopping a thread using boolean flag
 
class MyThread implements Runnable {
 
    // to stop the thread
    private boolean exit;
 
    private String name;
    Thread t;
 
    MyThread(String threadname)
    {
        name = threadname;
        t = new Thread(this, name);
        System.out.println("New thread: " + t);
        exit = false;
        t.start(); // Starting the thread
    }
 
    // execution of thread starts from run() method
    public void run()
    {
        int i = 0;
        while (!exit) {
            System.out.println(name + ": " + i);
            i++;
            try {
                Thread.sleep(100);
            }
            catch (InterruptedException e) {
                System.out.println("Caught:" + e);
            }
        }
        System.out.println(name + " Stopped.");
    }
 
    // for stopping the thread
    public void stop()
    {
        exit = true;
    }
}
 
// Main class
public class Main {
    public static void main(String args[])
    {
        // creating two objects t1 & t2 of MyThread
        MyThread t1 = new MyThread("First  thread");
        MyThread t2 = new MyThread("Second thread");
        try {
            Thread.sleep(500);
            t1.stop(); // stopping thread t1
            t2.stop(); // stopping thread t2
            Thread.sleep(500);
        }
        catch (InterruptedException e) {
            System.out.println("Caught:" + e);
        }
        System.out.println("Exiting the main Thread");
    }
}
Producción: 

New thread: Thread[First  thread, 5, main]
New thread: Thread[Second thread, 5, main]
First  thread: 0
Second thread: 0
First  thread: 1
Second thread: 1
First  thread: 2
Second thread: 2
First  thread: 3
Second thread: 3
First  thread: 4
Second thread: 4
First  thread: 5
Second thread Stopped.
First  thread Stopped.
Exiting the main Thread

 

Nota: La salida puede variar cada vez.
Al usar una bandera, podemos detener un hilo cuando queramos y podemos evitar errores de tiempo de ejecución no deseados.

  •  Uso de una bandera booleana volátil: también podemos usar una bandera booleana volátil para hacer que nuestro hilo de código sea seguro. Una variable volátil se almacena directamente en la memoria principal para que los subprocesos no puedan tener valores almacenados en caché localmente. Puede surgir una situación en la que más de un subproceso esté accediendo a la misma variable y los cambios realizados por uno podrían no ser visibles para otros subprocesos. En tal situación, podemos usar una bandera booleana volátil. 
    Consideremos el siguiente código donde usamos un indicador booleano no volátil:

Java

// Java program to illustrate non-volatile boolean flag
 
public class Main {
 
    // static used here
    // because a non-static variable
    // cannot be referenced
    // from a static context
 
    // exit variable to stop both
    // the main and inside threads
    static boolean exit = false;
 
    public static void main(String[] args)
    {
        System.out.println("started main thread..");
 
        // a thread inside main thread
        new Thread() {
            public void run()
            {
                System.out.println("started inside thread..");
 
                // inside thread caches the value of exit,
                // so changes made to exit are not visible here
                while (!exit) // will run infinitely
                {
                }
 
                // this will not be printed.
                System.out.println("exiting inside thread..");
            }
        }.start();
 
        try {
            Thread.sleep(500);
        }
        catch (InterruptedException e) {
            System.out.println("Caught :" + e);
        }
 
        // so that we can stop the threads
        exit = true;
        System.out.println("exiting main thread..");
    }
}

Errores de tiempo de ejecución: 

Time Limit Exceeded

Producción: 

started main thread..
started inside thread..
exiting main thread..

Nota: el código anterior se ejecuta en un bucle infinito y dará un error de tiempo de ejecución.
El resultado anterior muestra que el hilo interior nunca se detiene. Esto sucede porque el cambio realizado en la variable ‘salir’ en el subproceso principal no es visible para el subproceso interno. Esto es así porque el subproceso interno almacena en caché localmente el valor de exit. Para evitar que esto suceda, podemos usar una variable volátil. El siguiente código lo ilustra.

Java

// Java program to illustrate volatile boolean flag
 
public class Main {
 
    // static used here because
    // a non-static variable cannot be referenced
    // from a static context
 
    // exit variable to stop both
    // the main and inside threads
    static volatile boolean exit = false;
    public static void main(String[] args)
    {
 
        System.out.println("started main thread..");
 
        // a thread inside main thread
        new Thread() {
            public void run()
            {
 
                // changes made to exit
                // in main thread are visible here
                System.out.println("started inside thread..");
 
                // will not run infinitely
                while (!exit) {
                }
 
                // this will be printed
                System.out.println("exiting inside thread..");
            }
        }.start();
 
        try {
            Thread.sleep(500);
        }
        catch (InterruptedException e) {
            System.out.println("Caught :" + e);
        }
 
        // so that we can stop the threads
        exit = true;
        System.out.println("exiting main thread..");
    }
}
Producción: 

started main thread..
started inside thread..
exiting main thread..
exiting inside thread..

 

El resultado anterior muestra que cuando usamos un indicador booleano volátil, no nos encontramos con bucles infinitos. Esto se debe a que la variable volátil se almacena directamente en la memoria principal. En otras palabras, los cambios realizados por un subproceso son visibles para otros subprocesos. Por lo tanto, usar volatile hace que nuestro código sea seguro para subprocesos.
 

  • Usando el método Thread.interrupt(): cada vez que se envía una interrupción a un hilo, debe detener cualquier tarea que esté realizando. Es muy probable que cada vez que el subproceso reciba una interrupción, se termine. Esta acción se puede realizar utilizando el método interrupt(). Cada vez que se llama a Thread.interrupt(), establece un indicador conocido como el estado de interrupción en verdadero. Esto significa que el subproceso tiene que dejar de realizar más ejecuciones. El valor predeterminado de esta bandera es falso.

Java

// Java program to illustrate
// stopping a thread
// using the interrupt() method
 
class MyThread implements Runnable {
 
    Thread t;
 
    MyThread()
    {
        t = new Thread(this);
        System.out.println("New thread: " + t);
        t.start(); // Starting the thread
    }
 
    // execution of thread starts from run() method
    public void run()
    {
        while (!Thread.interrupted()) {
            System.out.println("Thread is running");
        }
        System.out.println("Thread has stopped.");
    }
}
 
// Main class
public class Main {
    public static void main(String args[])
    {
        // creating objects t1 of MyThread
        MyThread t1 = new MyThread();
 
        try {
            Thread.sleep(1);
 
            // t1 is an object of MyThread
            // which has an object t
            // which is of type Thread
            t1.t.interrupt();
 
            Thread.sleep(5);
        }
        catch (InterruptedException e) {
            System.out.println("Caught:" + e);
        }
        System.out.println("Exiting the main Thread");
    }
}
Producción: 

New thread: Thread[Thread-0, 5, main]
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread has stopped.
Exiting the main Thread

 

Nota: La salida puede variar cada vez. 

Publicación traducida automáticamente

Artículo escrito por Shivam_72 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *