Concorrência em Java (1) A postura correta para programação simultânea

Por que usar programação simultânea

Com o rápido desenvolvimento das CPUs atuais, foram lançadas CPUs de 4, 8 e até 16 núcleos. Na era das CPUs de núcleo único no passado, cada thread só pode competir por uma CPU para obter o direito de executar. No contexto de CPUs com vários núcleos, um thread não pode mais fazer uso completo de várias CPUs. Além disso, a era digital exacerbou os requisitos de desempenho do usuário para aplicativos.Os aplicativos tradicionais de thread único foram gradualmente eliminados e a execução simultânea de vários threads A forma da CPU pode maximizar o poder de computação da CPU , que é uma razão importante pela qual você precisa aprender programação simultânea.

A programação simultânea também tem desvantagens

Comutadores de contexto frequentes

Até os processadores de núcleo único suportam a execução de código multithread, e a CPU implementa a execução simultânea multithread alocando intervalos de tempo para cada thread. Ao executar o intervalo de tempo a tarefa A mudará para a próxima tarefa, neste momento necessidade de salvar o estado atual da tarefa A, quando o próximo turno para executar novamente a tarefa A necessidade de restaurar este estado, tal mudança de contexto é chamado para salvar e restaurar . A alternância frequente de contexto consumirá muitos recursos do sistema!

Existem maneiras de reduzir a alternância de contexto

  1. Programação simultânea sem bloqueio: você pode se referir à concurrentHashMapideia de segmentação de bloqueio, cada bloco corresponde a um segmento de dados e permite que diferentes threads processem diferentes segmentos de dados, para que, sob a condição de competição multithread, o tempo para a alternância de contexto possa ser reduzido.
  2. Algoritmo CAS: o pacote Atomic do Java usa o algoritmo CAS para atualizar dados sem bloquear.
  3. Use o menor número de threads: Evite criar threads desnecessários, para não causar um grande número de threads em um estado de espera.
  4. Corotina: obtenha agendamento de vários threads em um único thread e mantenha a alternância entre várias tarefas em um único thread.

Problemas de segurança do thread

Em um ambiente de programação simultâneo, os problemas de segurança que o multithreading pode trazer são:

  1. Impasse do encadeamento: cada encadeamento espera um pelo outro para liberar os recursos que está ocupando.
  2. Inanição de encadeamento: os encadeamentos nunca podem obter fatias de tempo da CPU e estão sempre em um estado de espera.
public class DeadLockDemo {
    private static String resource_a = "A";
    private static String resource_b = "B";

    public static void main(String[] args) {
        deadLock();
    }
    public static void deadLock() {
        Thread threadA = new Thread(()->{
            synchronized (resource_a) {
                    System.out.println("get resource a");
                    try {
                        Thread.sleep(3000);
                        synchronized (resource_b) {
                            System.out.println("get resource b");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        });
        Thread threadB = new Thread(()->{
            synchronized (resource_b) {
                    System.out.println("get resource b");
                    synchronized (resource_a) {
                        System.out.println("get resource a");
                    }
                }
        });
        threadA.start();
        threadB.start();
    }
}
复制代码

O código acima demonstra a cena do impasse. Observando jpso número do processo e o jstackstatus do encadeamento do aplicativo, é possível ver que os dois encadeamentos aguardam os recursos que o outro está ocupando, mas não liberam os recursos, causando uma espera permanente um pelo outro.

Vários métodos comuns para evitar conflitos:

  1. Evite um encadeamento solicitando a aquisição de vários bloqueios ao mesmo tempo
  2. Adicione números aos recursos, os threads só podem adquirir bloqueios em ordem de acordo com os números
  3. O tempo para adquirir o bloqueio mais um valor de período , não permita que o encadeamento solicite permanentemente o bloqueio
  4. O algoritmo do banqueiro, antes de alocar o bloqueio, determina se ele causará um conflito , se houver, e então rejeita a solicitação de aquisição do bloqueio.

Conceitos a entender antes de aprender programação simultânea

Síncrona e assíncrona

Sincronização: após o método A chamar o método B, é necessário aguardar a conclusão da execução do método B antes de continuar o método A.

Assíncrono: depois que o método A chama o método B, o método A pode continuar processando sua própria lógica de negócios sem esperar pelo método B concluir a execução.

Por exemplo, durante as compras extras, se um item estiver esgotado, é necessário aguardar que a equipe do armazém transfira as mercadorias com você.Até a equipe do armazém enviar as mercadorias para você, você poderá continuar pagando no caixa. E a chamada assíncrona é como compras on-line. Depois de fazer um pedido on-line, você não precisa se preocupar com nada. Você deve optar pelo que deseja. Quando as mercadorias chegarem, você receberá uma notificação para recebê-la.

Concorrência e paralelismo

Simultaneidade: vários segmentos são executados continuamente alternadamente e apenas um segmento está sendo executado ao mesmo tempo .

Paralelismo: no verdadeiro sentido, vários threads são executados ao mesmo tempo , e vários threads são atribuídos a várias CPUs para serem executados juntos ao mesmo tempo .

Por exemplo, em uma CPU de núcleo único, não há conceito de execução paralela de encadeamentos, apenas o conceito de execução simultânea. Como vários threads devem compartilhar uma CPU, a CPU alterna constantemente o contexto do thread para permitir que diferentes threads sejam executados (muito cansados). Em uma CPU com vários núcleos, vários threads podem ser alocados para diferentes CPUs para serem executadas simultaneamente ao mesmo tempo.

Bloqueio e não bloqueio

Bloqueio: se um encadeamento A ocupa o recurso X, quando o encadeamento B solicita a operação do recurso X, ele deve aguardar o encadeamento A liberar o recurso X. O processo de espera é chamado de bloqueio.

Sem bloqueio: Semelhante ao exemplo acima, exceto que o encadeamento B não precisa aguardar o lançamento do encadeamento A ao solicitar a operação do recurso X. Vários encadeamentos podem acessar o recurso X à vontade.

Região crítica

A seção crítica é usada para representar um recurso comum ou dados compartilhados que podem ser acessados ​​por vários encadeamentos. No entanto, quando cada thread opera nos recursos críticos da seção, uma vez que os recursos críticos da seção são ocupados por um thread, os outros threads devem esperar.

Por exemplo CopyOnWriteArrayList, em Java, esse recurso crítico não será bloqueado ao ler dados, mas a coleção inteira será bloqueada quando os dados forem adicionados, excluídos ou atualizados.Outros encadeamentos devem esperar que o encadeamento conclua a operação antes de acessar.

Sumário

Esses são alguns conceitos importantes que devem ser entendidos antes da entrada em programação simultânea; o domínio desses conceitos será muito útil para o próximo estudo! Continuarei atualizando a série simultânea de artigos no futuro. Espero me comunicar com você. Se este artigo ajudar um pouco, seus pequenos elogios me farão feliz o dia todo! Obrigado pela leitura!

Ombro do gigante:

"A arte da programação simultânea em Java"

github.com/CL0610/Java…

Acho que você gosta

Origin juejin.im/post/5e9f8994e51d4546fc797628
Recomendado
Clasificación