Concorrência em Java: Como implementar StampedLocks para controle de acesso

Por Gaspar Barancelli Junior em 12 de maio de 2024
Imagem ilustrativa sobre o post Concorrência em Java: Como implementar StampedLocks para controle de acesso

Quando se trata de programação concorrente em Java, a sincronização eficiente entre threads é crucial para a performance e a segurança das aplicações. Além dos tradicionais synchronized e ReentrantLock, o Java 8 trouxe uma nova opção: o StampedLock. Este post irá explorar o que são StampedLocks, como eles podem ser utilizados e quais vantagens eles oferecem.

O que é StampedLock?

O StampedLock é uma ferramenta de bloqueio que foi introduzida no Java 8 como parte do pacote java.util.concurrent.locks. Diferente dos ReentrantLocks, StampedLocks oferecem um modelo de bloqueio baseado em estampas (stamps) que representam estados de bloqueio. Isso permite controlar leituras e escritas com mais flexibilidade e menor overhead em cenários de leitura mais frequentes.

Como funciona o StampedLock?

Ao contrário do bloqueio ReentrantLock, o StampedLock não é reentrante, o que significa que a mesma thread não pode adquirir um StampedLock mais de uma vez sem liberá-lo, evitando assim o deadlock causado por uma programação descuidada. A grande vantagem dos StampedLocks é a possibilidade de converter um bloqueio de leitura em um bloqueio de escrita sem comprometer a atomicidade.

O que é atomicidade?

A atomicidade, no contexto de StampedLock e programação concorrente, refere-se à propriedade de uma operação ser completada integralmente sem ser interrompida por outras operações. Em outras palavras, uma operação atômica ocorre como uma única unidade indivisível, sem estado intermediário visível. Isso é crucial para evitar erros e comportamentos inesperados em ambientes multithread, onde múltiplas operações podem tentar modificar o mesmo recurso simultaneamente.

Exemplo

Depositando em uma Conta

Vamos começar com um exemplo prático que demonstra como usar StampedLock para controle de acesso a um recurso compartilhado, como um saldo de conta:

import java.util.concurrent.locks.StampedLock;

public class Conta {
    private final StampedLock bloqueio = new StampedLock();
    private double saldo = 0.0;

    public void depositar(double valor) {
        long carimbo = bloqueio.writeLock(); // Bloqueio de escrita
        try {
            saldo += valor;
        } finally {
            bloqueio.unlockWrite(carimbo); // Desbloqueio de escrita
        }
    }

    public double obterSaldo() {
        long carimbo = bloqueio.tryOptimisticRead(); // Tentativa de leitura otimista
        double saldoAtual = saldo;
        if (!bloqueio.validate(carimbo)) { // Valida se o carimbo ainda é válido
            carimbo = bloqueio.readLock(); // Obtém um bloqueio de leitura
            try {
                saldoAtual = saldo;
            } finally {
                bloqueio.unlockRead(carimbo); // Desbloqueio de leitura
            }
        }
        return saldoAtual;
    }
}
Ajustando o Saldo

Agora, veja como um bloqueio de leitura pode ser convertido em um bloqueio de escrita, útil quando uma verificação durante a leitura determina que uma modificação é necessária:

public void ajustarSaldo(double ajuste) {
    long carimbo = bloqueio.readLock(); // Bloqueio de leitura
    try {
        while (true) {
            double saldoAtual = saldo;
            double novoSaldo = saldoAtual + ajuste;
            long ws = bloqueio.tryConvertToWriteLock(carimbo); // Tenta converter para bloqueio de escrita
            if (ws != 0L) {
                carimbo = ws;
                saldo = novoSaldo;
                return;
            } else {
                bloqueio.unlockRead(carimbo); // Desbloqueio de leitura
                carimbo = bloqueio.writeLock(); // Novo bloqueio de escrita
            }
        }
    } finally {
        bloqueio.unlock(carimbo); // Desbloqueio geral
    }
}

Conclusão

StampedLock é uma excelente opção ao lidar com concorrência em Java, oferecendo uma forma de controle de acesso mais granular com potencial para melhorar a performance em cenários de leitura intensiva. No entanto, é crucial entender suas particularidades e limitações, especialmente o fato de não ser reentrante, o que exige cuidado adicional para evitar deadlocks. Além disso, a capacidade de converter leituras em escritas pode ser extremamente útil em situações onde a carga de trabalho é variável e a eficiência é crítica.

// Compartilhe esse Post

💫
🔥 NOVO APP

Domine o Inglês em 30 dias!

Inteligência Artificial + Repetição Espaçada • Método cientificamente comprovado

✅ Grátis para começar 🚀 Resultados rápidos
×