JavaRush /Blog Java /Random-ES /Pausa para el café #112. Cómo declarar, inicializar e ite...

Pausa para el café #112. Cómo declarar, inicializar e iterar sobre una matriz en Java. ¿Cómo detener un hilo de Java sin usar Thread.stop()?

Publicado en el grupo Random-ES

Cómo declarar, inicializar e iterar sobre una matriz en Java

Fuente: FreeCodeCamp En este artículo hablaremos sobre matrices en Java. Veremos algunos ejemplos para ayudarle a comprender qué es una matriz, cómo declararla y cómo usarla en código Java. Pausa para el café #112.  Cómo declarar, inicializar e iterar sobre una matriz en Java.  ¿Cómo detener un hilo de Java sin usar Thread.stop()?  - 1

¿Qué es una matriz?

En Java, usamos una matriz para almacenar múltiples valores del mismo tipo de datos en una sola variable. También se puede considerar como una colección de valores del mismo tipo de datos. Esto significa que si va a almacenar cadenas en su matriz, por ejemplo, entonces todos los valores de su matriz deben ser cadenas.

Cómo declarar una matriz en Java

Usamos corchetes [ ] para declarar una matriz . Como eso:
String[] names;
Aquí hemos declarado una variable llamada nombres que contendrá una serie de cadenas. Si necesitamos declarar una variable para números enteros (enteros), lo haremos así:
int[] myIntegers;
Entonces, para crear una matriz, especificamos el tipo de datos que se almacenarán en la matriz, seguido de corchetes y luego el nombre de la matriz.

Cómo inicializar una matriz en Java

Inicializar una matriz significa asignar valores a la matriz. Inicialicemos las matrices que declaramos en la sección anterior:
String[] names = {"John", "Jade", "Love", "Allen"};
int[] myIntegers = {10, 11, 12};
Inicializamos nuestras matrices pasando valores del mismo tipo de datos, separando cada valor con una coma. Si quisiéramos acceder a los elementos/valores de nuestra matriz, accederíamos a su número de índice en la matriz. El índice del primer elemento es 0. Aquí hay un ejemplo:
String[] names = {"John", "Jade", "Love", "Allen"};

System.out.println(names[0]);
// John

System.out.println(names[1]);
// Jade

System.out.println(names[2]);
// Love

System.out.println(names[3]);
// Allen
Ahora que sabemos cómo acceder a cada elemento, cambiemos el valor del tercer elemento.
String[] names = {"John", "Jade", "Love", "Allen"};
names[2] = "Victor";

System.out.println(names[2]);
// Victor
También podemos verificar la longitud de una matriz usando la propiedad de longitud . He aquí un ejemplo:
String[] names = {"John", "Jade", "Love", "Allen"};
System.out.println(names.length);
// 4

Cómo iterar a través de una matriz en Java

Podemos usar un bucle for para recorrer los elementos de una matriz .
String[] names = {"John", "Jade", "Love", "Allen"};
for (int i = 0; i < names.length; i++) {
  System.out.println(names[i]);
}

// John
// Jade
// Love
// Allen
El bucle anterior imprimirá los elementos de nuestra matriz. Usamos la propiedad de longitud para especificar cuántas veces debe ejecutarse el bucle.

Conclusión

En este artículo, aprendimos cómo declarar e inicializar matrices en código Java. También vimos cómo acceder a cada elemento de una matriz y cómo recorrer esos elementos. ¡Feliz codificación!

¿Cómo detener un hilo de Java sin usar Thread.stop()?

Fuente: 4comprehension Si estás leyendo esto, probablemente te estés preguntando por qué y, lo más importante, cómo detener un hilo si no puedes confiar simplemente en el método Thread#stop() , que ha quedado obsoleto desde Java 1.2. ? Pausa para el café #112.  Cómo declarar, inicializar e iterar sobre una matriz en Java.  ¿Cómo detener un hilo de Java sin usar Thread.stop()?  - 2La respuesta corta es que deberías utilizar interrupciones porque Thread#stop no es seguro. Pero si quieres entender por qué, cómo y para qué sirve esa molesta InterruptedException , sigue leyendo.

Problema con Thread#stop()

No importa lo intuitivo que pueda parecer, interrumpir un hilo que ya se está ejecutando, iniciar y detener son dos casos completamente diferentes. ¿Por qué? Cuando iniciamos un nuevo hilo, comenzamos desde cero, que es un estado bien definido, pero cuando intentamos detener un hilo existente, puede suceder en medio de una operación que no se puede interrumpir inmediatamente . Imagine un hilo realizando cambios en una estructura de datos segura para hilos. Mientras está en el medio de la sección crítica... y luego el hilo desaparece mágicamente: los bloqueos se liberan y ahora otro hilo puede observar la estructura de datos que queda en un estado inconsistente. Considere el siguiente ejemplo de un contador seguro para subprocesos con algún estado interno:
class ThreadSafeCounter {

    private volatile int counter = 0;
    private volatile boolean dirty = false;

    public synchronized int incrementAndGet() {
        if (dirty) {
            throw new IllegalStateException("this should never happen");
        }
        dirty = true;
        // ...
        Thread.sleep(5000); // boilerplate not included
        // ...
        counter = counter + 1;
        dirty = false;
        return counter;
    }
}
Como puede ver, el método getAndIncrement() incrementa el contador y cambia la bandera sucia . Los bloqueos garantizan que cada vez que un hilo ingresa a getAndIncrement() la bandera sucia se establece en false . Ahora creemos un hilo y detengámoslo abruptamente:
var threadSafeCounter = new ThreadSafeCounter();

var t1 = new Thread(() -> {
    while (true) {
        threadSafeCounter.incrementAndGet();
    }
});

t1.start();
Thread.sleep(500);
t1.stop();

threadSafeCounter.incrementAndGet();

// Exception in thread "main" java.lang.IllegalStateException: this should never happen
Ahora la instancia de threadSafeCounter , a pesar de estar implementada correctamente, está permanentemente dañada debido a que el hilo se detuvo abruptamente. ¿Como arreglarlo?

Interrupción de hilo cooperativo

En lugar de detener el hilo, deberíamos confiar en la interrupción cooperativa del hilo. En pocas palabras, debemos pedirle al hilo que se detenga en el momento adecuado usando Thread#interrupt . Sin embargo, llamar a Thread#interrupt en lugar de Thread#stop no es suficiente. La terminación segura de un hilo solo se puede lograr mediante el uso de una interrupción de hilo compartido, lo que significa que dentro del hilo necesitamos manejar señales de interrupción, que son de dos tipos:
  • Bandera booleana interrumpida

  • Excepción interrumpida

Manejo de banderas interrumpibles

Mientras estamos dentro de un hilo, podemos verificar si ha sido interrumpido llamando a uno de los métodos:
Thread.currentThread().isInterrupted(); // reads the interrupted flag
Thread.interrupted(); // reads and resets the interrupted flag
Dado que no existe una forma universal de manejar una interrupción, debemos aplicar una acción que se adapte a nuestro contexto. En el ejemplo de la sección anterior, el hilo incrementa nuestro contador en un bucle infinito. En lugar de detenernos inmediatamente, podríamos simplemente esperar a que el hilo complete su trabajo ascendente y luego salir del ciclo:
var threadSafeCounter = new ThreadSafeCounter();

var t1 = new Thread(() -> {
    while (!Thread.interrupted()) {
        threadSafeCounter.incrementAndGet();
    }
});

t1.start();
Thread.sleep(500);
t1.interrupt();

threadSafeCounter.incrementAndGet();
Ahora el hilo termina de forma segura en el momento adecuado sin causar caos.

Manejo de excepción interrumpida

¿Qué pasa si intentamos interrumpir un hilo en espera? Naturalmente, no podemos tener en cuenta el indicador de interrupción porque el hilo está ocupado con una operación de bloqueo. Por eso existe InterruptedException . ¡Esta no es una excepción estándar, sino una forma diferente de señal de interrupción que existe únicamente para manejar interrupciones de bloqueo! Al igual que Thread#interrupted , restablece el indicador de interrupción . Cambiemos nuevamente el ejemplo anterior e introduzcamos pausas antes de cada incremento. Ahora necesitamos manejar la InterruptedException lanzada por Thread#sleep :
var threadSafeCounter = new ThreadSafeCounter();

var t1 = new Thread(() -> {
    while (!Thread.interrupted()) {
        threadSafeCounter.incrementAndGet();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            break;
        }
    }
});

t1.start();
Thread.sleep(500);
t1.interrupt();

assertThat(threadSafeCounter.incrementAndGet()).isGreaterThan(0);
En nuestro caso, fue suficiente simplemente salir del bucle. Pero, ¿qué pasa si no cree que un método específico deba ser responsable de manejar las interrupciones? ¿Qué pasa si no se puede cambiar la firma del método? En este caso, necesitamos restaurar el indicador de interrupción y/o volver a empaquetar la excepción, por ejemplo:
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    throw new RuntimeException(e);
}

Conclusión:

  • Thread#stop no está obsoleto sin ningún motivo; en realidad, es muy inseguro.

  • Los subprocesos se detienen mediante interrupciones: señales interpretadas por el propio subproceso.

  • InterruptedException no es una excepción ordinaria: es la forma integrada de Java de señalar que un hilo ha sido interrumpido.

  • Thread.currentThread().isInterrupted() y Thread.interrupted() no son lo mismo. El primero simplemente lee el indicador de interrupción y el otro lo restablece después.

  • No existe una forma universal de manejar las señales de interrupción: "depende de las circunstancias".

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION