CodeGym/Cursos Java/Módulo 3/Padrões multithread

Padrões multithread

Disponível

3.1 Objeto ativo

Um objeto Active é um padrão de design que separa o thread de execução de um método do thread no qual ele foi chamado. A finalidade desse padrão é fornecer execução paralela usando chamadas de método assíncronas e um agendador de processamento de solicitação.

Versão simplificada:

objeto ativo

Variante clássica:

Objeto ativo 2

Este modelo tem seis elementos:

  • Um objeto proxy que fornece uma interface para os métodos públicos do cliente.
  • Uma interface que define métodos de acesso para o objeto ativo.
  • Lista de solicitações recebidas de clientes.
  • Um agendador que determina a ordem na qual as consultas devem ser executadas.
  • Implementação de métodos de objetos ativos.
  • Um procedimento de retorno de chamada ou uma variável para o cliente receber um resultado.

3.2 bloqueio

O padrão Lock é um mecanismo de sincronização que permite acesso exclusivo a um recurso compartilhado entre vários threads. Os bloqueios são uma maneira de impor a política de controle de simultaneidade.

Basicamente, um soft lock é usado, com a suposição de que cada thread tente “adquirir o bloqueio” antes de acessar o recurso compartilhado correspondente.

No entanto, alguns sistemas fornecem um mecanismo de bloqueio obrigatório pelo qual uma tentativa de acesso não autorizado a um recurso bloqueado será abortada lançando uma exceção no thread que tentou obter acesso.

Um semáforo é o tipo mais simples de bloqueio. Ao nível do acesso aos dados não é feita qualquer distinção entre os modos de acesso: partilhado (leitura-só) ou exclusivo (leitura-escrita). No modo compartilhado, vários threads podem solicitar um bloqueio para acessar dados no modo somente leitura. O modo de acesso exclusivo também é usado nos algoritmos de atualização e exclusão.

padrão de bloqueio

Os tipos de bloqueios se diferenciam pela estratégia de bloquear a continuação da execução da thread. Na maioria das implementações, uma solicitação de bloqueio impede que o encadeamento continue a executar até que o recurso bloqueado esteja disponível.

Um spinlock é um bloqueio que espera em um loop até que o acesso seja concedido. Tal bloqueio é muito eficiente se um thread espera por um bloqueio por um pequeno período de tempo, evitando assim o reescalonamento excessivo de threads. O custo de espera pelo acesso será significativo se uma das threads mantiver o bloqueio por muito tempo.

padrão de bloqueio 2

Para implementar efetivamente o mecanismo de bloqueio, é necessário suporte no nível do hardware. O suporte de hardware pode ser implementado como uma ou mais operações atômicas, como "testar e definir", "buscar e adicionar" ou "comparar e trocar". Essas instruções permitem que você verifique sem interrupção se o bloqueio está livre e, em caso afirmativo, adquira o bloqueio.

3.3 Monitorar

O padrão Monitor é um mecanismo de interação e sincronização de processo de alto nível que fornece acesso a recursos compartilhados. Uma abordagem para sincronizar duas ou mais tarefas de computador usando um recurso comum, geralmente hardware ou um conjunto de variáveis.

Na multitarefa baseada em monitor, o compilador ou interpretador insere de forma transparente o código de bloqueio-desbloqueio em rotinas formatadas apropriadamente, de forma transparente para o programador, evitando que o programador chame explicitamente as primitivas de sincronização.

O monitor é composto por:

  • um conjunto de procedimentos que interagem com um recurso compartilhado
  • mutex
  • variáveis ​​associadas a este recurso
  • uma invariante que define condições para evitar uma condição de corrida

O procedimento monitor adquire o mutex antes de iniciar o trabalho e o mantém até que o procedimento termine ou até que uma determinada condição seja esperada. Se cada procedimento garantir que a invariante seja verdadeira antes de liberar o mutex, nenhuma tarefa poderá adquirir o recurso em uma condição de corrida.

É assim que o operador sincronizado funciona em Java com os métodos wait()e notify().

3.4 Bloqueio de verificação dupla

O bloqueio verificado duas vezes é um padrão de design paralelo destinado a reduzir a sobrecarga de obtenção de um bloqueio.

Primeiro, a condição de bloqueio é verificada sem nenhuma sincronização. Um thread tenta adquirir um bloqueio somente se o resultado da verificação indicar que ele precisa adquirir o bloqueio.

//Double-Checked Locking
public final class Singleton {
private static Singleton instance; //Don't forget volatile modifier

public static Singleton getInstance() {
     if (instance == null) {                //Read

         synchronized (Singleton.class) {    //
             if (instance == null) {         //Read Write
                 instance = new Singleton(); //
             }
         }
     }
 }

Como criar um objeto singleton em um ambiente thread-safe?

public static Singleton getInstance() {
   if (instance == null)
    instance = new Singleton();
}

Se você criar um objeto Singleton de diferentes threads, pode haver uma situação em que vários objetos são criados ao mesmo tempo, e isso é inaceitável. Portanto, é razoável agrupar a criação do objeto em uma instrução sincronizada.

public static Singleton getInstance() {
    synchronized (Singleton.class) {
        if (instance == null)
        instance = new Singleton();
    }
}

Essa abordagem funcionará, mas tem uma pequena desvantagem. Após a criação do objeto, toda vez que você tentar obtê-lo no futuro, será realizada uma verificação no bloco sincronizado, o que significa que o thread atual e tudo relacionado a ele serão bloqueados. Portanto, este código pode ser otimizado um pouco:

public static Singleton getInstance() {
     if (instance != null)
        return instance;

    synchronized (Singleton.class) {
        if (instance == null)
        instance = new Singleton();
    }
}

Em algumas linguagens e/ou em algumas máquinas não é possível implementar esse padrão com segurança. Portanto, às vezes é chamado de antipadrão. Tais recursos levaram ao aparecimento do relacionamento de ordem estrita "acontece antes" no Modelo de Memória Java e no Modelo de Memória C++.

É normalmente usado para reduzir a sobrecarga de implementação de inicialização preguiçosa em programas multiencadeados, como o padrão de design Singleton. Na inicialização preguiçosa de uma variável, a inicialização é adiada até que o valor da variável seja necessário no cálculo.

3.5 Agendador

O Agendador é um padrão de design paralelo que fornece um mecanismo para implementar uma política de agendamento, mas é independente de qualquer política específica. Controla a ordem na qual os threads devem executar o código sequencial, usando um objeto que especifica explicitamente a sequência de threads em espera.

1
Tarefa
Módulo 3,  nível 17lição 2
Bloqueado
Trust, but Verify
task4123
Comentários
  • Populares
  • Novas
  • Antigas
Você precisa acessar para deixar um comentário
Esta página ainda não tem nenhum comentário