JavaRush /Blogue Java /Random-PT /Pausa para café #112. Como declarar, inicializar e iterar...

Pausa para café #112. Como declarar, inicializar e iterar sobre um array em Java. Como parar um thread Java sem usar Thread.stop()?

Publicado no grupo Random-PT

Como declarar, inicializar e iterar sobre um array em Java

Fonte: FreeCodeCamp Neste artigo falaremos sobre arrays em Java. Veremos alguns exemplos para ajudá-lo a entender o que é um array, como declará-lo e como usá-lo no código Java. Pausa para café #112.  Como declarar, inicializar e iterar sobre um array em Java.  Como parar um thread Java sem usar Thread.stop()?  - 1

O que é uma matriz?

Em Java, usamos um array para armazenar vários valores do mesmo tipo de dados em uma única variável. Também pode ser pensado como uma coleção de valores do mesmo tipo de dados. Isso significa que se você for armazenar strings em seu array, por exemplo, todos os valores em seu array deverão ser strings.

Como declarar um array em Java

Usamos colchetes [] para declarar um array . Assim:
String[] names;
Aqui declaramos uma variável chamada nomes que conterá um array de strings. Se precisarmos declarar uma variável para inteiros (inteiros), faremos assim:
int[] myIntegers;
Assim, para criar um array, especificamos o tipo de dado que será armazenado no array, seguido de colchetes e depois o nome do array.

Como inicializar um array em Java

Inicializar um array significa atribuir valores ao array. Vamos inicializar os arrays que declaramos na seção anterior:
String[] names = {"John", "Jade", "Love", "Allen"};
int[] myIntegers = {10, 11, 12};
Inicializamos nossos arrays passando valores do mesmo tipo de dados, separando cada valor com uma vírgula. Se quiséssemos acessar os elementos/valores em nosso array, acessaríamos seu número de índice no array. O índice do primeiro elemento é 0. Aqui está um exemplo:
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
Agora que sabemos como acessar cada elemento, vamos alterar o valor do terceiro elemento.
String[] names = {"John", "Jade", "Love", "Allen"};
names[2] = "Victor";

System.out.println(names[2]);
// Victor
Também podemos verificar o comprimento de um array usando a propriedade length . Aqui está um exemplo:
String[] names = {"John", "Jade", "Love", "Allen"};
System.out.println(names.length);
// 4

Como iterar através de um array em Java

Podemos usar um loop for para iterar pelos elementos de um array .
String[] names = {"John", "Jade", "Love", "Allen"};
for (int i = 0; i < names.length; i++) {
  System.out.println(names[i]);
}

// John
// Jade
// Love
// Allen
O loop acima irá imprimir os elementos do nosso array. Usamos a propriedade length para especificar quantas vezes o loop deve ser executado.

Conclusão

Neste artigo, aprendemos como declarar e inicializar arrays em código Java. Também vimos como acessar cada elemento de um array e como percorrer esses elementos. Boa codificação!

Como parar um thread Java sem usar Thread.stop()?

Fonte: 4comprehension Se você está lendo isso, provavelmente está se perguntando por que e, o mais importante, como interromper um thread se não pode simplesmente confiar no método Thread#stop() , que está obsoleto desde Java 1.2 ? Pausa para café #112.  Como declarar, inicializar e iterar sobre um array em Java.  Como parar um thread Java sem usar Thread.stop()?  - 2A resposta curta é que você deve usar interrupções porque Thread#stop não é seguro. Mas se você quiser entender por que, como e para que serve essa irritante InterruptedException , continue lendo.

Problema com Thread#stop()

Por mais intuitivo que possa parecer, interromper um thread já em execução, iniciar e parar são dois casos completamente diferentes. Por que? Quando iniciamos um novo thread, estamos começando do zero, que é um estado bem definido, mas quando tentamos interromper um thread existente, isso pode acontecer no meio de uma operação que não pode ser interrompida imediatamente . Imagine um thread fazendo alterações em uma estrutura de dados segura para thread. Enquanto está no meio da seção crítica... e então o thread desaparece magicamente - os bloqueios são liberados e agora outro thread pode observar a estrutura de dados deixada em um estado inconsistente. Considere o seguinte exemplo de um contador thread-safe com algum 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 você pode ver, o método getAndIncrement() incrementa o contador e altera o sinalizador sujo . Os bloqueios garantem que toda vez que um thread entrar em getAndIncrement() o sinalizador sujo seja definido como false . Agora vamos criar um tópico e interrompê-lo 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
Agora a instância threadSafeCounter , apesar de ter sido implementada corretamente, está permanentemente corrompida devido ao thread ter sido interrompido abruptamente. Como corrigi-lo?

Interrupção Cooperativa de Thread

Em vez de interromper o thread, devemos contar com a interrupção cooperativa do thread. Simplificando, devemos pedir ao thread que pare no momento certo usando Thread#interrupt . No entanto, chamar Thread#interrupt em vez de Thread#stop não é suficiente. O encerramento seguro de um thread só pode ser alcançado usando uma interrupção de thread compartilhada, o que significa que dentro do thread precisamos lidar com sinais de interrupção, que vêm em dois tipos:
  • Sinalizador booleano interrompido

  • Exceção Interrompida

Tratamento de sinalizadores interrompíveis

Enquanto estivermos dentro de um thread, podemos verificar se ele foi interrompido chamando um dos métodos:
Thread.currentThread().isInterrupted(); // reads the interrupted flag
Thread.interrupted(); // reads and resets the interrupted flag
Como não existe uma maneira universal de lidar com uma interrupção, precisamos aplicar uma ação adequada ao nosso contexto. No exemplo da seção anterior, o thread incrementa nosso contador em um loop infinito. Em vez de parar imediatamente, poderíamos simplesmente esperar que o thread conclua seu trabalho ascendente e então sair do loop:
var threadSafeCounter = new ThreadSafeCounter();

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

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

threadSafeCounter.incrementAndGet();
Agora o thread termina com segurança no momento certo, sem causar caos.

Tratamento de exceção interrompida

O que acontece se tentarmos interromper um thread em espera? Naturalmente, não podemos levar em consideração o sinalizador de interrupção porque o thread está ocupado com uma operação de bloqueio. É por isso que existe InterruptedException . Esta não é uma exceção padrão, mas uma forma diferente de sinal de interrupção que existe apenas para lidar com interrupções de bloqueio! Assim como Thread#interrupted , ele redefine o sinalizador de interrupção . Vamos mudar o exemplo acima novamente e introduzir pausas antes de cada incremento. Agora precisamos lidar com a InterruptedException lançada 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);
No nosso caso, bastava simplesmente sair do loop. Mas e se você não achar que um método específico deva ser responsável por lidar com interrupções? e se a assinatura do método não puder ser alterada? Neste caso, precisamos restaurar o sinalizador de interrupção e/ou reempacotar a exceção, por exemplo:
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    throw new RuntimeException(e);
}

Conclusão:

  • Thread#stop não está obsoleto sem motivo - na verdade, é muito inseguro.

  • Threads são interrompidos por meio de interrupções – sinais interpretados pelo próprio thread.

  • InterruptedException não é uma exceção comum - é a maneira integrada do Java de sinalizar que um thread foi interrompido.

  • Thread.currentThread().isInterrupted() e Thread.interrupted() não são a mesma coisa. O primeiro simplesmente lê o sinalizador de interrupção e o outro o reinicia posteriormente.

  • Não existe uma maneira universal de lidar com sinais de interrupção – “depende das circunstâncias”.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION