não entendo porque esse erro IllegalMonitorStateException

2 respostas
bruno_r_santana

blz pessoal?

Então, estava testando algumas coisas de Threads para me preparar para certificação. Aqui tem um exemplo funcional usando wait, notify e usando bloco sincronizado dentro de um construtor, o que é permitido. Só não pode ter um construtor synchronized. Vejam o código e a saída:

class MinhaThread extends Thread{
    String[] sincronizador;
    
    public MinhaThread(String[] sincronizador) {
        this.sincronizador = sincronizador;
    }
    
    public void run(){
        synchronized(sincronizador){
            while(!sincronizador[0].equals("finish")){
                try{
                    System.out.println("entrou no bloco sincronizado da classe MinhaThread");
                    sincronizador.wait();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
        System.out.println("saiu do modo wait");
    }
}


class Dispara{
    String[] sincronizador = {"sinc"};
    
    Dispara(){
        Thread mt = new MinhaThread(sincronizador);
        mt.start();
        try{
            Thread.sleep(3000);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        synchronized(sincronizador){
            System.out.println("entrou no bloco sinc da classe Dispara");
            sincronizador[0] = "finish";
            sincronizador.notify();
            System.out.println("depois do notify");
        }
    }
}

public class BlocoSincDentroConst {
    public static void main(String args[]){
        System.out.println("main");
        new Dispara();
    }
}

main
entrou no bloco sincronizado da classe MinhaThread
entrou no bloco sinc da classe Dispara
depois do notify
saiu do modo wait
CONSTRUÍDO COM SUCESSO (tempo total: 3 segundos)

Agora se eu modificar o mesmo exemplo acima mudando de um array de String para uma String simples passa a dar erro IllegalMonitorStateException:

class MinhaThread extends Thread{
    String sincronizador;
    
    public MinhaThread(String sincronizador) {
        this.sincronizador = sincronizador;
    }
    
    public void run(){
        synchronized(sincronizador){
            while(!sincronizador.equals("finish")){
                try{
                    System.out.println("entrou no bloco sincronizado da classe MinhaThread");
                    sincronizador.wait();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
        System.out.println("saiu do modo wait");
    }
}


class Dispara{
    String sincronizador = "sinc";
    
    Dispara(){
        Thread mt = new MinhaThread(sincronizador);
        mt.start();
        try{
            Thread.sleep(3000);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        synchronized(sincronizador){
            System.out.println("entrou no bloco sinc da classe Dispara");
            sincronizador = "finish";
            sincronizador.notify();
            System.out.println("depois do notify");
        }
    }
}

public class BlocoSincDentroConst {
    public static void main(String args[]){
        System.out.println("main");
        new Dispara();
    }
}

main
entrou no bloco sincronizado da classe MinhaThread
entrou no bloco sinc da classe Dispara
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at certificacao.thread.Dispara.(BlocoSincDentroConst.java:50)
at certificacao.thread.BlocoSincDentroConst.main(BlocoSincDentroConst.java:59)
CONSTRUÇÃO PARADA (tempo total: 11 segundos)

Alguém pode me explicar por favor porque funciona com array de String mas não com String?

Obrigado.

2 Respostas

E
// antes desta linha, a variável "sincronizador" tinha um determinado objeto que era o sendo usado pelo "synchronized"
            sincronizador = "finish";  
            // a linha anterior mudou o objeto, portanto a linha seguinte vai dar problemas:
            sincronizador.notify();

Conselho: se for usar synchronized, use um Object puro e simples, e não o mude durante a sincronização. Eu costumo usar:

Object lock = new Object();
...
synchronized (lock) {
    ...
bruno_r_santana

Obrigado entanglement, eu havia lida a resposta faz tempo mas não tinha tido tempo de agradecer. Entendi o motivo da exceção. valeu!

Criado 16 de dezembro de 2012
Ultima resposta 23 de dez. de 2012
Respostas 2
Participantes 2