Concurrencia de Java - Políticas de interrupción

Aug 26 2020

Estoy leyendo Java Concurrency in Practice . En la sección Políticas de Interrupción en el capítulo

Cancelación y Apagado

Su mencionado

Una tarea no debe asumir nada sobre la política de interrupción de su subproceso en ejecución, a menos que esté diseñada explícitamente para ejecutarse dentro de un servicio que tenga una política de interrupción específica. Ya sea que una tarea interprete la interrupción como una cancelación o tome alguna otra acción sobre la interrupción, debe tener cuidado de preservar el estado de interrupción del subproceso en ejecución. Si no va a propagar InterruptedException a quien llama, debería restaurar el estado de interrupción después de capturar InterruptionException: Thread.currentThread().interrupt()

Así que traté de jugar con la lista de muestra para entender. Pero estoy confundido con la salida.

Productor principal

public class CorrectPrimeProducer extends Thread {

    private final BlockingQueue<BigInteger> queue;

    public CorrectPrimeProducer(BlockingQueue<BigInteger> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            System.out.println(Thread.currentThread().getName()+" interrupt status in producer:" + Thread.currentThread().isInterrupted());
            BigInteger p = BigInteger.ONE;
            while (!Thread.currentThread().isInterrupted()) {
                queue.put(p = p.nextProbablePrime());
            }
        } catch (InterruptedException e) {
            /* Allow thread to exit */
            Thread.currentThread().interrupt();
            System.out.println(Thread.currentThread().getName()+" interrupt status in producer catch:" + Thread.currentThread().isInterrupted());
        }
    }
}

método principal##

public static void main(String[] args) throws InterruptedException {
        BlockingQueue<BigInteger> primes = new LinkedBlockingQueue<>();
        CorrectPrimeProducer generator = new CorrectPrimeProducer(primes);
        generator.start();
        try {
            while (needMorePrimes()) {
                consume(primes.take());
            }
        } finally {
            generator.interrupt();
        }
        TimeUnit.SECONDS.sleep(5);
        System.out.println(generator.getName()+" interrupt status in main:"+generator.isInterrupted());
    }

    //do something
    private static void consume(BigInteger take) {
        System.out.println(take);
    }

    private static int counter = 1;

    private static boolean needMorePrimes() {
        counter++;
        if(counter == 10){
// after counter reaches 10 return false
            return false;
        }
        return true; 
    }

Producción:

// when TimeUnit.SECONDS.sleep(5); in main class is not commented

Thread-0 interrupt status in producer:false
2
3
5
7
11
13
17
19
Thread-0 interrupt status in producer catch:true
Thread-0 interrupt status in main:false
//When TimeUnit.SECONDS.sleep(5); in main class is commented
Thread-0 interrupt status in producer:false
2
3
5
7
11
13
17
19
Thread-0 interrupt status in main:true
Thread-0 interrupt status in producer catch:true

Pregunta

  1. Simplemente agregando TimeUnit.SECONDS.sleep(5) en el hilo principal en la clase principal. El estado de interrupción del subproceso en ejecución (es decir, el generador) se está restableciendo. Si comento el método TimeUnit.SECONDS.sleep(5), en ese caso se conserva el estado de interrupción. ¿Por qué sucede esto y cómo?

  2. En el libro se menciona que un hilo debe ser interrumpido solo por su propietario. Aquí, en el ejemplo anterior, ¿quién es el propietario? Creo que su hilo de método principal.

Respuestas

1 Joni Aug 26 2020 at 04:25

Al agregar TimeUnit.SECONDS.sleep(5), está dando suficiente tiempo para que el hilo termine.

Cuando un subproceso termina, su bandera de interrupción se borra.

Esto no está documentado en la especificación, pero es lo que sucede. Vea, por ejemplo , este informe de error :

Aquí no se viola ninguna especificación, así que hice de esto una solicitud de mejora en lugar de un error. Podría decirse que la falta de especificación es un error: especificamos intencionalmente que "la interrupción después de la terminación no tiene por qué afectar" para lidiar con el hecho de que el estado de interrupción se almacena en la VM y ya no existe una vez que finaliza un hilo. Sin embargo, olvidamos reflejar eso en la especificación Thread.isInterrupted.

Sin el extra sleep, sospecho que, en teoría, podría ver tanto el estado truecomo falseel de interrupción porque hay una condición de carrera, pero es mucho más probable que lo vea truegracias a la programación de subprocesos. La ventana de tiempo en la que el estado de interrupción es falso, entre que se lanza la excepción y se restaura el estado de interrupción en el bloque catch, es increíblemente pequeña.

2 michalk Aug 26 2020 at 03:49

Simplemente agregando TimeUnit.SECONDS.sleep(5) en el hilo principal en la clase principal. El estado de interrupción del subproceso en ejecución (es decir, el generador) se está restableciendo. Si comento el método TimeUnit.SECONDS.sleep(5), en ese caso se conserva el estado de interrupción. ¿Por qué sucede esto y cómo?

No está utilizando ningún mecanismo de sincronización (aparte de bloquear la cola) entre el subproceso principal y el subproceso principal, CorrectPrimeProducerpor lo que cuando el subproceso principal imprime el estado, CorrectPrimeProduceres posible que aún no haya conservado el estado interrumpido (realizando catchinstrucciones de bloqueo), por lo que obtiene falsecomo resultado.

Cuando agrega sleepal principal Thread, simplemente aumenta la posibilidad de que el CorrectPrimeProducersubproceso conserve el estado de interrupción al invocar catchinstrucciones de bloque antes de que el subproceso principal intente imprimir su estado. Por eso se imprime true.

En el libro se menciona que un hilo debe ser interrumpido solo por su propietario. Aquí, en el ejemplo anterior, ¿quién es el propietario? Creo que su hilo de método principal.

En este caso, usted es el propietario (el propietario es el código que crea el hilo) del CorrectPrimeProducerhilo, por lo que decide qué significa la interrupción para él. Por ejemplo, podría volver a crearlo si se interrumpiera (esto sucede, por ejemplo, para Threadlos correos electrónicos de los grupos de subprocesos de Java de forma predeterminada).