Como corrigir ReentrantLock causando IllegalMonitorStateException?

IllegalMonitorStateException ocorre ao usar ReentrantLock sem adquirir o bloqueio corretamente antes de chamar métodos de sincronização.

Como corrigir ReentrantLock causando IllegalMonitorStateException?

O erro IllegalMonitorStateException ao usar ReentrantLock ocorre quando tentamos chamar métodos de sincronização como await(), signal() ou signalAll() sem adquirir o bloqueio corretamente. Diferente do synchronized, ReentrantLock exige que o lock seja explicitamente adquirido e liberado.

Causas comuns do erro com ReentrantLock

Tentar chamar await() ou signal() sem bloquear o lock. Liberar um lock que não foi adquirido pela mesma thread. Não utilizar lock() antes de manipular condições.

Exemplo de erro e solução

Código que gera o erro:

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

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

    public static void main(String[] args) {
        condition.signal(); // Lançará IllegalMonitorStateException pois não há lock adquirido
    }
}

O erro ocorre porque signal() foi chamado sem antes adquirir o bloqueio.

Correção:

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

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

    public static void main(String[] args) {
        lock.lock(); // Adquirindo o lock antes de chamar signal()
        try {
            condition.signal();
        } finally {
            lock.unlock(); // Sempre liberar o lock
        }
    }
}

A solução correta é garantir que o lock foi adquirido antes de chamar métodos de condição.

Como evitar IllegalMonitorStateException ao usar ReentrantLock?

Sempre utilize lock.lock() antes de chamar await(), signal() ou signalAll(). Garanta que o lock seja liberado corretamente utilizando try-finally. Evite liberar um lock que não foi adquirido pela mesma thread.

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

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

    public static void main(String[] args) {
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Thread aguardando...");
                condition.await();
                System.out.println("Thread despertada!");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock.unlock();
            }
        }).start();

        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Sinalizando thread...");
                condition.signal();
            } finally {
                lock.unlock();
            }
        }).start();
    }
}

Conclusão

O erro IllegalMonitorStateException ao usar ReentrantLock pode ser evitado garantindo que o lock seja sempre adquirido antes de chamar await(), signal() ou signalAll(). O uso correto de try-finally também é essencial para evitar deadlocks e garantir que o bloqueio seja liberado adequadamente.

ReentrantLock é uma alternativa poderosa ao synchronized para manipulação de concorrência em Java, mas seu uso incorreto pode levar a erros como IllegalMonitorStateException. Esse erro ocorre quando métodos como await() ou signal() são chamados sem que o lock tenha sido adquirido corretamente. Para evitar problemas, sempre garanta que a thread tenha o lock antes de manipular condições.

Algumas aplicações:

  • Garantir controle seguro sobre concorrência em Java
  • Evitar erros ao manipular múltiplas threads
  • Melhorar a sincronização de processos paralelos
  • Controlar corretamente sinais e bloqueios entre threads

Dicas para quem está começando

  • Sempre adquira o lock antes de chamar await() ou signal()
  • Use try-finally para liberar o lock corretamente
  • Evite liberar locks em threads diferentes da que os adquiriu
  • Utilize Condition ao invés de wait() e notify() quando estiver usando ReentrantLock

Contribuições de Rodrigo Farias

Compartilhe este tutorial: Como corrigir ReentrantLock causando IllegalMonitorStateException

Compartilhe este tutorial

Continue aprendendo:

O que significa IllegalMonitorStateException e como resolver esse erro

IllegalMonitorStateException ocorre quando um thread tenta chamar wait(), notify() ou notifyAll() sem possuir o monitor do objeto.

Tutorial anterior

Por que meu código está lançando UnsupportedEncodingException

UnsupportedEncodingException ocorre quando uma codificação de caracteres inválida ou não suportada é usada em Java.

Próximo tutorial