23. Sincronização e Bloqueios em Java

A programação concorrente em Java é um tópico avançado e crucial para o desenvolvimento de aplicações robustas e eficientes. No entanto, com a execução de múltiplas threads acessando recursos compartilhados, surgem desafios relacionados à consistência dos dados e à coordenação entre as threads. Para lidar com esses desafios, Java fornece mecanismos de sincronização e bloqueios.

O Problema da Concorrência

Quando múltiplas threads operam em dados compartilhados sem a devida sincronização, podem ocorrer condições de corrida (race conditions), onde os resultados da execução dependem da ordem não determinística em que as threads são executadas. Isso pode levar a comportamentos imprevisíveis e a bugs difíceis de reproduzir e corrigir.

Mecanismos de Sincronização

Para evitar condições de corrida, Java oferece mecanismos de sincronização que permitem controlar o acesso aos recursos compartilhados. O principal constructo para sincronização em Java é a palavra-chave synchronized, que pode ser usada para sincronizar um bloco de código ou um método inteiro.

Métodos Sincronizados

Quando um método é declarado como sincronizado, ele garante que apenas uma thread por vez possa executá-lo em uma instância da classe. Se o método é estático, o bloqueio é no nível da classe, não da instância.


public synchronized void metodoSincronizado() {
    // Código que manipula recurso compartilhado
}

Blocos Sincronizados

Em vez de sincronizar um método inteiro, é possível sincronizar apenas uma seção crítica do código usando um bloco sincronizado. Isso é feito especificando um objeto de bloqueio, sobre o qual o bloqueio é mantido.


public void metodoComBlocoSincronizado() {
    synchronized (this) {
        // Seção crítica do código
    }
}

Monitores e Bloqueios Inerentes

Em Java, cada objeto possui um bloqueio inerente ou monitor, que é utilizado para implementar a sincronização. Quando uma thread entra em um método ou bloco sincronizado, ela adquire o bloqueio associado ao objeto ou classe. Outras threads que tentarem acessar o mesmo bloco ou método sincronizado serão bloqueadas até que a thread atual libere o bloqueio.

Locks Explícitos

Além dos bloqueios inerentes, a API de concorrência de Java (java.util.concurrent) fornece uma série de classes de bloqueio explícitas que oferecem mais flexibilidade e controle. As classes ReentrantLock, ReadWriteLock e StampedLock são alguns exemplos.


import java.util.concurrent.locks.ReentrantLock;

public class ExemploLock {
    private final ReentrantLock lock = new ReentrantLock();

    public void metodoComLock() {
        lock.lock();
        try {
            // Código protegido pelo lock
        } finally {
            lock.unlock();
        }
    }
}

Os bloqueios explícitos oferecem recursos adicionais, como a capacidade de tentar adquirir um bloqueio sem esperar indefinidamente (tryLock), a possibilidade de interromper uma thread enquanto ela espera por um bloqueio (lockInterruptibly) e a capacidade de verificar se o bloqueio está sendo mantido (isLocked).

Condições e Sincronização Fina

Com a classe ReentrantLock, você também pode criar uma ou mais Condition que fornecem uma forma de sincronização mais fina, permitindo que as threads aguardem condições específicas ou notifiquem outras threads sobre mudanças de estado.


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ExemploCondition {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public void aguardarCondicao() throws InterruptedException {
        lock.lock();
        try {
            // Espera até que a condição seja satisfeita
            condition.await();
        } finally {
            lock.unlock();
        }
    }

    public void sinalizarCondicao() {
        lock.lock();
        try {
            // Sinaliza uma thread que está esperando pela condição
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}

Considerações de Desempenho

A sincronização tem um custo associado em termos de desempenho, pois ela pode reduzir a concorrência e aumentar o tempo de espera das threads. Portanto, é importante utilizar a sincronização de forma ponderada e eficiente, protegendo apenas as seções críticas do código e evitando bloqueios desnecessários.

Boas Práticas

  • Minimize o escopo dos blocos sincronizados para reduzir o tempo em que os bloqueios são mantidos.
  • Evite realizar operações de I/O ou chamadas de rede dentro de blocos sincronizados, pois isso pode causar atrasos significativos.
  • Considere o uso de coleções da API java.util.concurrent, que são projetadas para serem usadas em ambientes concorrentes sem a necessidade de sincronização externa.
  • Esteja ciente de deadlocks, que podem ocorrer quando duas ou mais threads estão esperando indefinidamente umas pelas outras para liberar bloqueios.

Conclusão

A sincronização e os bloqueios são ferramentas essenciais para a programação concorrente em Java, permitindo que os desenvolvedores gerenciem o acesso a recursos compartilhados e evitem condições de corrida. No entanto, é importante usar esses mecanismos com cuidado e conhecimento, pois eles podem afetar o desempenho da aplicação e levar a problemas complexos, como deadlocks. Com uma compreensão sólida dos conceitos de sincronização e das APIs fornecidas por Java, os desenvolvedores podem criar aplicações concorrentes seguras e eficientes.

Agora responda o exercício sobre o conteúdo:

Qual das seguintes afirmações sobre sincronização e bloqueios em Java está correta?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Imagem do artigo Padrões de design e princípios do SOLID

Próxima página do Ebook Gratuito:

119Padrões de design e princípios do SOLID

4 minutos

Ganhe seu Certificado deste Curso Gratuitamente! ao baixar o aplicativo Cursa e ler o ebook por lá. Disponível na Google Play ou App Store!

Disponível no Google Play Disponível no App Store

+ de 6,5 milhões
de alunos

Certificado Gratuito e
Válido em todo o Brasil

48 mil exercícios
gratuitos

4,8/5 classificação
nas lojas de apps

Cursos gratuitos em
vídeo, áudio e texto