Por que ocorrem condições de corrida de threads e quais métodos existem para combatê-las?
sobes.tech IA
Resposta da IA
Condições de corrida (race conditions) ocorrem quando vários threads acedem simultaneamente a dados modificáveis partilhados, e o resultado depende da ordem de execução. Isto acontece porque o sistema operativo pode alternar entre threads a qualquer momento, interrompendo a sua execução.
Formas de combater:
-
Sincronização: Uso de primitivas de sincronização para garantir acesso exclusivo a recursos partilhados.
-
Palavra-chave
synchronized: Aplicada a métodos ou blocos de código. Bloqueia o acesso a um objeto ou classe para outros threads até que o thread atual termine de executar o bloco/método sincronizado.// Sincronização de método public synchronized void updateData(int newValue) { // ... atualização de dados partilhados } // Sincronização de bloco de código public void processData() { synchronized (this) { // Ou qualquer outro objeto monitor // ... acesso a dados partilhados } } -
Locks (
Lock): Oferecem um controlo mais flexível sobre a sincronização em comparação comsynchronized.import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; private final Lock dataLock = new ReentrantLock(); public void safeUpdateData(int newValue) { dataLock.lock(); // Aquisição do lock try { // ... atualização de dados partilhados } finally { dataLock.unlock(); // Liberação do lock } }
-
-
Variáveis atómicas (
Atomic...): Proporcionam operações seguras para threads sobre tipos primitivos sem bloqueio explícito. Usadas para operações simples (incremento, comparação e troca).import java.util.concurrent.atomic.AtomicInteger; private final AtomicInteger counter = new AtomicInteger(0); public void incrementCounter() { counter.incrementAndGet(); // Incremento atómico } -
Coleções seguras para threads: Uso de coleções especiais do pacote
java.util.concurrent(por exemplo,ConcurrentHashMap,CopyOnWriteArrayList), projetadas para acesso concorrente.import java.util.concurrent.ConcurrentHashMap; import java.util.Map; private final Map<String, Integer> safeMap = new ConcurrentHashMap<>(); -
Objetos imutáveis (Immutable): Se os dados não mudam após a criação, podem ser acessados com segurança por múltiplos threads sem sincronização.
-
Variáveis locais de thread (
ThreadLocal): Cada thread recebe uma cópia da variável, evitando competição por acesso.private final ThreadLocal<Integer> threadId = new ThreadLocal<>(); public void setThreadId() { threadId.set(Thread.currentThread().getId()); } public int getThreadId() { return threadId.get(); } -
Design arquitetónico correto: Minimizar dados modificáveis partilhados e usar abordagens assíncronas ou transmissão de mensagens entre threads pode reduzir a probabilidade de condições de corrida.