Método Java para terminar el hilo correctamente

Hay un método stop () obsoleto en la clase Thread, que puede terminar el hilo, pero debido a que termina directamente el hilo independientemente del número de pasos, está obsoleto. Por ejemplo, después de detener el hilo, se requieren algunas operaciones posteriores (como cerrar los recursos externos) y no hay nada que pueda hacer con este método. La terminación del hilo se puede lograr mediante la interrupción del hilo.

Primero observe algunos de los contenidos de la interrupción del hilo de Java:

  • La plataforma Java mantiene una bandera de interrupción booleana para cada subproceso, y el valor de la bandera se puede obtener mediante los siguientes métodos:
    interrupt () interrumpe un subproceso
    isInterrupted () devuelve la bandera de interrupción del subproceso
    interrumpido () devuelve y restablece el subproceso Indicador de interrupción (establecido en falso)

  • La interrupción es solo una solicitud del subproceso iniciador al subproceso de destino, es decir, el subproceso de destino puede responder a esta solicitud o ignorarla.

  • Todos los métodos relacionados con el bloqueo de subprocesos en la biblioteca estándar de Java arrojan excepciones InterruptedException en respuesta a las interrupciones y, por convención, el indicador de interrupción se restablece a falso antes de lanzar una excepción, por lo que estos métodos borrarán el indicador de interrupción del subproceso.

  • Los métodos relacionados con el bloqueo de subprocesos en la biblioteca estándar de Java determinarán si la bandera de interrupción es verdadera antes del bloqueo, y lanzarán una excepción si es verdadera; si se llama al método de interrupción después del bloqueo, entonces la JVM establecerá la bandera de interrupción del subproceso, y luego el subproceso se despierta, por lo que la interrupción tiene el efecto de despertar el subproceso.

De los puntos anteriores y la segunda oración en negrita, se puede ver que la interrupción del hilo se puede usar para lograr la terminación del hilo, siempre que el hilo de destino juzgue la marca de interrupción, incluso si el hilo interrumpido está en un estado bloqueado, puede ser despertado y terminado; De la primera oración en negrita, se puede ver que el uso directo de interrupciones de subprocesos para lograr la terminación de subprocesos es arriesgado, porque se pueden llamar algunos métodos de bloqueo de la biblioteca estándar de Java, y se borra el indicador de interrupción, y el No se puede obtener el indicador de interrupción (el total es falso), por lo que debe crear un indicador de interrupción para usarlo.

Por ejemplo, el siguiente es un ejecutor de tareas interrumpible. Antes de que se ejecute cada tarea, se determinará la marca de terminación de la i autodefinida y el número de tareas restantes (secuelas); el método de apagado proporcionado es además de interrumpir al trabajador hilo (principalmente La función es despertar tareas que pueden estar en un estado bloqueado) y establecer la intersección de terminación terminada en verdadero.

Al ejecutar el método principal, puede encontrar que imprimirá "El cliente ha llamado al método de cierre" primero, y luego el hilo principal terminará después de cuatro segundos. Se puede ver que el método de cierre finaliza correctamente el hilo de destino. Con respecto a "De acuerdo con la convención, los métodos de bloqueo relacionados con subprocesos que arrojan InterruptedException en la biblioteca estándar de Java borrarán el indicador de interrupción", puede reemplazar! Interminated en la condición con! Thread.currentThread (). IsInterrupted (), y luego ejecutar la prueba del método principal, se puede encontrar que el hilo principal no se puede terminar, porque el método sleep () borra el indicador de interrupción, por lo que! Thread.currentThread (). isInterrupted () siempre es verdadero, lo que hace que el hilo de trabajo no pueda para terminar.

public class TerminableTaskRunner {
    // 存储要执行的任务
    private final BlockingQueue<Runnable> tasks;
    // 线程终止标志
    private volatile boolean terminated;
    // 剩余的任务数
    private final AtomicInteger count;
    // 实际执行任务的线程
    private volatile Thread workThread;
 
    public TerminableTaskRunner(int capacity) {
        this.tasks = new LinkedBlockingDeque<>(capacity);
        this.count = new AtomicInteger(0);
        this.workThread = new WorkThread();
        workThread.start();
    }
 
    public void submit(Runnable task) {
        this.tasks.add(task);
        this.count.incrementAndGet();
    }
 
    public void shutdown() {
        terminated = true; // 线程终止标志,由于中断标志可能会被覆盖,所以需要自己创建一个标志
        if (workThread != null)
            workThread.interrupt(); // 唤醒线程
    }
 
    private class WorkThread extends Thread {
        @Override
        public void run() {
            Runnable task;
            try {
                while (!terminated || tasks.size() >= 1) {
                    task = tasks.take();
                    try {
                        task.run(); // 可能会清空当前线程的中断标记,如task.run()在内部调用的阻塞方法抛出了InterruptedException
                    } catch (Throwable e) {
                        e.printStackTrace();
                    }
                    count.decrementAndGet();
                }
            } catch (InterruptedException e) {
                // 一旦调用shutdown且tasks.take()阻塞住,就抛出该异常,没有任务要执行,直接终止
                workThread = null;
            }
        }
    }
 
    public static void main(String[] args) {
        TerminableTaskRunner taskRunner = new TerminableTaskRunner(4);
        for (int i = 0; i < 4; i++) {
            taskRunner.submit(()->{
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    System.out.println("客户端调用了 shutdown 方法");
                }
            });
        }
        taskRunner.shutdown();
 
    }
}

Algunas preguntas de entrevistas de alta frecuencia recopiladas en el último 2020 (todas organizadas en documentos), hay muchos productos secos, incluidos mysql, netty, spring, thread, spring cloud, jvm, código fuente, algoritmo y otras explicaciones detalladas, así como planes de aprendizaje detallados, entrevistas Clasificación de preguntas, etc. Para aquellos que necesitan obtener estos contenidos, agregue Q como: 11604713672

Supongo que te gusta

Origin blog.csdn.net/weixin_51495453/article/details/114754567
Recomendado
Clasificación