JavaRush /Blogue Java /Random-PT /Pausa para café #113. 5 coisas que você provavelmente não...

Pausa para café #113. 5 coisas que você provavelmente não sabia sobre multithreading em Java. 10 extensões JetBrains para combater dívidas técnicas

Publicado no grupo Random-PT

5 coisas que você provavelmente não sabia sobre multithreading em Java

Fonte: DZone Thread é o coração da linguagem de programação Java. Até mesmo a execução do programa Hello World precisa do thread principal. Se necessário, podemos adicionar outros threads ao programa se quisermos que o código do nosso aplicativo seja mais funcional e de desempenho. Se estamos falando de um servidor web, ele processa simultaneamente centenas de solicitações simultaneamente. Vários threads são usados ​​para isso. Pausa para café #113.  5 coisas que você provavelmente não sabia sobre multithreading em Java.  10 extensões JetBrains para combater dívidas técnicas - 1Threads são sem dúvida úteis, mas trabalhar com eles pode ser difícil para muitos desenvolvedores. Neste artigo, compartilharei cinco conceitos de multithreading que desenvolvedores novos e experientes talvez não conheçam.

1. A ordem do programa e a ordem de execução não correspondem

Quando escrevemos código, presumimos que ele será executado exatamente da maneira que o escrevemos. No entanto, na realidade este não é o caso. O compilador Java pode alterar a ordem de execução para otimizá-la se puder determinar que a saída não mudará no código de thread único. Observe o seguinte trecho de código:
package ca.bazlur.playground;

import java.util.concurrent.Phaser;

public class ExecutionOrderDemo {
    private static class A {
        int x = 0;
    }

    private static final A sharedData1 = new A();
    private static final A sharedData2 = new A();

    public static void main(String[] args) {
        var phaser = new Phaser(3);
        var t1 = new Thread(() -> {
            phaser.arriveAndAwaitAdvance();
            var l1 = sharedData1;
            var l2 = l1.x;
            var l3 = sharedData2;
            var l4 = l3.x;
            var l5 = l1.x;
            System.out.println("Thread 1: " + l2 + "," + l4 + "," + l5);
        });
        var t2 = new Thread(() -> {
            phaser.arriveAndAwaitAdvance();
            var l6 = sharedData1;
            l6.x = 3;
            System.out.println("Thread 2: " + l6.x);
        });
        t1.start();
        t2.start();
        phaser.arriveAndDeregister();
    }
}
Este código parece simples. Temos duas instâncias de dados compartilhados ( sharedData1 e sharedData2 ) que usam dois threads. Quando executamos o código, esperamos que a saída seja assim:
Tópico 2: 3 Tópico 1: 0,0,0
Mas se você executar o código várias vezes, verá um resultado diferente:
Linha 2: 3 Linha 1: 3,0,3 Linha 2: 3 Linha 1: 0,0,3 Linha 2: 3 Linha 1: 3,3,3 Linha 2: 3 Linha 1: 0,3,0 Linha 2 : 3 Fio 1: 0,3,3
Não estou dizendo que todos esses streams serão reproduzidos exatamente assim na sua máquina, mas é perfeitamente possível.

2. O número de threads Java é limitado

Criar um thread em Java é fácil. No entanto, isso não significa que podemos criar quantos quisermos. O número de threads é limitado. Podemos descobrir facilmente quantos threads podemos criar em uma máquina específica usando o seguinte programa:
package ca.bazlur.playground;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

public class Playground {
    public static void main(String[] args) {
        var counter = new AtomicInteger();
        while (true) {
            new Thread(() -> {
                int count = counter.incrementAndGet();
                System.out.println("thread count = " + count);
                LockSupport.park();
            }).start();
        }
    }
}
O programa acima é muito simples. Ele cria um thread em um loop e depois o estaciona, o que significa que o thread está desabilitado para uso futuro, mas executa uma chamada de sistema e aloca memória. O programa continua a criar threads até que não consiga mais criar e então lança uma exceção. Estamos interessados ​​no número que receberemos até que o programa lance uma exceção. No meu computador só consegui criar 4.065 threads.

3. Muitos threads não garantem melhor desempenho

É ingênuo acreditar que facilitar threads em Java melhorará o desempenho do aplicativo. Infelizmente, essa suposição está errada com nosso modelo tradicional de multithreading que o Java oferece hoje. Na verdade, muitos threads podem reduzir o desempenho de um aplicativo. Vamos primeiro fazer esta pergunta: qual é o número máximo ideal de threads que podemos criar para maximizar o desempenho do aplicativo? Bem, a resposta não é tão simples. Depende muito do tipo de trabalho que fazemos. Se tivermos várias tarefas independentes, todas computacionais e sem bloquear nenhum recurso externo, ter um grande número de threads não melhorará muito o desempenho. Por outro lado, se tivermos um processador de 8 núcleos, o número ideal de threads poderia ser (8 + 1). Nesse caso, podemos contar com o thread paralelo introduzido no Java 8. Por padrão, o thread paralelo usa o pool Fork/Join compartilhado. Ele cria threads iguais ao número de processadores disponíveis, o que é suficiente para que funcionem intensamente. Adicionar mais threads a um trabalho com uso intensivo de CPU, onde nada está bloqueado, não melhorará o desempenho. Em vez disso, simplesmente desperdiçaremos recursos. Observação. A razão para ter um thread extra é que mesmo um thread com uso intensivo de computação às vezes causa uma falha de página ou é suspenso por algum outro motivo. (Consulte: Java Parallelism in Practice , Brian Goetz, página 170) No entanto, suponha, por exemplo, que as tarefas sejam vinculadas a E/S. Neste caso, eles dependem de comunicação externa (por exemplo, banco de dados, outras APIs), portanto, um número maior de threads faz sentido. O motivo é que quando um thread está aguardando na API Rest, outros threads podem continuar funcionando. Agora podemos perguntar novamente: quantos threads são demais para esse caso? Depende. Não existem números perfeitos que sirvam para todos os casos. Portanto, devemos fazer testes adequados para descobrir o que funciona melhor para nossa carga de trabalho e aplicação específica. No cenário mais típico, normalmente temos um conjunto misto de tarefas. E nesses casos as coisas chegam ao fim. Em seu livro “Java Concurrency in Practice”, Brian Goetz propôs uma fórmula que podemos usar na maioria dos casos. Número de threads = Número de núcleos disponíveis * (1 + Tempo de espera/Tempo de serviço) O tempo de espera pode ser IO, como esperar por uma resposta HTTP, adquirir um bloqueio e assim por diante. Tempo de serviço(Tempo de serviço) é o tempo de computação, como processamento de uma resposta HTTP, empacotamento/desempacotamento e assim por diante. Por exemplo, um aplicativo chama uma API e a processa. Se tivermos 8 processadores no servidor de aplicação, o tempo médio de resposta da API é de 100 ms e o tempo de processamento de resposta é de 20 ms, então o tamanho ideal do thread seria:
N = 8 * (1 + 100/20) = 48
No entanto, isto é uma simplificação excessiva; testes adequados são sempre críticos para determinar o número.

4. Multithreading não é paralelismo

Às vezes usamos multithreading e paralelismo de forma intercambiável, mas isso não é mais totalmente relevante. Embora em Java consigamos ambos usando um thread, são duas coisas diferentes. “Na programação, o multithreading é um caso especial, independentemente dos processos em execução, e o paralelismo é a execução simultânea de cálculos (possivelmente relacionados). Multithreading é interagir com muitas coisas ao mesmo tempo. A simultaneidade está fazendo muitas coisas ao mesmo tempo.” A definição acima dada por Rob Pike é bastante precisa. Digamos que temos tarefas completamente independentes e que podem ser calculadas separadamente. Neste caso, essas tarefas são chamadas de paralelas e podem ser executadas com um pool Fork/Join ou uma thread paralela. Por outro lado, se tivermos muitas tarefas, algumas delas podem depender de outras. A forma como compomos e estruturamos é chamada de multithreading. Tem a ver com estrutura. Podemos querer realizar diversas tarefas simultaneamente para alcançar determinado resultado, sem necessariamente terminar uma mais rápido.

5. O Projeto Loom nos permite criar milhões de threads

No ponto anterior, argumentei que ter mais threads não significa melhorar o desempenho do aplicativo. No entanto, na era dos microsserviços, interagimos com muitos serviços para realizar qualquer trabalho específico. Nesse cenário, os threads permanecem bloqueados na maior parte do tempo. Embora um sistema operacional moderno possa lidar com milhões de soquetes abertos, não podemos abrir muitos canais de comunicação, pois estamos limitados pelo número de threads. Mas e se você criar milhões de threads e cada um deles usar um soquete aberto para se comunicar com o mundo exterior? Isso definitivamente melhorará o rendimento do nosso aplicativo. Para apoiar essa ideia, existe uma iniciativa em Java chamada Project Loom. Usando-o, podemos criar milhões de threads virtuais. Por exemplo, usando o trecho de código a seguir, consegui criar 4,5 milhões de threads em minha máquina.
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

public class Main {
    public static void main(String[] args) {
        var counter = new AtomicInteger();

        // 4_576_279
        while (true) {
            Thread.startVirtualThread(() -> {
                int count = counter.incrementAndGet();
                System.out.println("thread count = " + count);
                LockSupport.park();
            });
        }
    }
}
Para executar este programa é necessário ter o Java 18 instalado, que pode ser baixado aqui . Você pode executar o código usando o seguinte comando: java --source 18 --enable-preview Main.java

10 extensões JetBrains para combater dívidas técnicas

Fonte: DZone Muitas equipes de desenvolvimento sentem uma enorme pressão para cumprir prazos. Por causa disso, muitas vezes eles não têm tempo suficiente para consertar e limpar sua base de código. Às vezes, nessas situações, a dívida técnica se acumula rapidamente. As extensões do editor podem ajudar a resolver esse problema. Vamos dar uma olhada nas 10 melhores extensões JetBrains para combater dívidas técnicas (com suporte Java). Pausa para café #113.  5 coisas que você provavelmente não sabia sobre multithreading em Java.  10 extensões JetBrains para combater dívidas técnicas - 2

Ferramentas de refatoração e dívida técnica

1. RefactorInsight

O RefactorInsight melhora a visibilidade das alterações de código no IDE, fornecendo informações sobre refatorações.
  1. A extensão define refatorações em solicitações de mesclagem.
  2. Marca commits que contêm refatorações.
  3. Ajuda na visualização da refatoração de qualquer commit específico selecionado na aba Git Log.
  4. Mostra o histórico de refatoração de classes, métodos e campos.

2. Rastreador de problemas Stepsize no IDE

Stepsize é um ótimo rastreador de problemas para desenvolvedores. A extensão ajuda os engenheiros não apenas a criar TODOs e comentários de código melhores, mas também a priorizar dívidas técnicas, refatorações e assim por diante:
  1. Stepsize permite criar e visualizar tarefas em código diretamente no editor.
  2. Encontre problemas que afetam os recursos nos quais você está trabalhando.
  3. Adicione problemas aos seus sprints usando integrações Jira, Asana, Linear, Azure DevOps e GitHub.

3. Nova Relíquia CodeStream

New Relic CodeStream é uma plataforma de colaboração de desenvolvedores para discussão e revisão de código. Ele suporta solicitações pull do GitHub, BitBucket e GitLab, gerenciamento de problemas do Jira, Trello, Asana e 9 outros, e fornece discussões de código, unindo tudo.
  1. Crie, revise e mescle solicitações pull no GitHub.
  2. Obtenha feedback sobre o trabalho em andamento com revisões preliminares de código.
  3. Discutir problemas de código com colegas de equipe.

TODO e comentários

4. Marcador de comentários

Este plugin permite criar destaques personalizados de linhas de comentários e palavras-chave de idioma. O plugin também tem a capacidade de definir tokens personalizados para destacar linhas de comentários.

5. Melhores comentários

A extensão Better Comments ajuda a criar comentários mais claros em seu código. Com esta extensão você poderá classificar suas anotações em:
  1. Alertas.
  2. Solicitações de.
  3. PENDÊNCIA.
  4. Momentos básicos.

Bugs e vulnerabilidades de segurança

6.SonarLint _

SonarLint permite solucionar problemas de código antes que eles surjam. Também pode ser usado como corretor ortográfico. O SonarLint destaca bugs e vulnerabilidades de segurança à medida que você codifica, com instruções claras de correção para que você possa corrigi-los antes que o código seja confirmado.

7. SpotBugs

O plugin SpotBugs fornece análise estática de bytecode para encontrar bugs no código Java do IntelliJ IDEA. SpotBugs é uma ferramenta de detecção de defeitos para Java que usa análise estática para encontrar mais de 400 padrões de bugs, como desreferências de ponteiro nulo, loops recursivos infinitos, uso indevido de bibliotecas Java e impasses. SpotBugs pode identificar centenas de defeitos graves em aplicações grandes (normalmente cerca de 1 defeito por 1.000 a 2.000 linhas de instruções brutas não comentadas).

8. Verificador de vulnerabilidade Snyk

O Vulnerability Scanner do Snyk ajuda a encontrar e corrigir vulnerabilidades de segurança e problemas de qualidade de código em seus projetos.
  1. Encontrar e corrigir problemas de segurança.
  2. Veja uma lista de diferentes tipos de problemas, divididos em categorias.
  3. Exibe dicas de solução de problemas.

9. Localizador de caracteres de largura zero

Este plugin aprimora a verificação e detecção de erros difíceis de encontrar relacionados a caracteres invisíveis de largura zero no código-fonte e nos recursos. Ao usar, certifique-se de que a verificação “Caracter unicode de largura zero” esteja habilitada.

10.CódigoMR_ _

CodeMR é uma ferramenta de qualidade de software e análise estática de código que ajuda empresas de software a desenvolver códigos e programas melhores. CodeMR visualiza métricas de código e atributos de qualidade de alto nível (acoplamento, complexidade, coesão e tamanho) em várias visualizações, como estrutura de pacote, TreeMap, Sunburst, dependência e visualizações de gráfico.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION