Porque o estado de múltiplas Threads não é mantido mesmo quando usando Singleton?

3 respostas
gutostraube

Olá!

Estava desenvolvendo alguns estudos envolvendo Threads e Singletons e cheguei a um problema que não consegui entender.

Criei um Singleton que implementa a interface Runnable. O meu Singleton tem um atributo privado que armazena seu estado de execução (running). Quando executo meu programa, por meio de uma Thread, o status é alterado. Até aqui, tudo certo.

O meu problema está quando faço uma segunda execução em paralelo. O estado não é armazenado e a exceção (IllegalStateException) não é lançada.

Já tentei tornar o atributo running estático, mas não resolveu. Acredito que seja falta de entendimento ou visualização de algum conceito que esteja me impedindo de pensar em uma solução. Vocês conseguem ver alguma possibilidade?

Para simular o problema, compile e execute o código abaixo (reserve, rs) e execute novamente, em paralelo, o programa. As duas execuções ficaram esperando algo da entrada padrão. Sendo que o esperado é que a segunda execução lance uma exceção.

import java.util.Scanner;

public class Singleton implements Runnable {

    private static final Singleton singleton = new Singleton();

    private boolean running;

    public static void main(String[] args) {
        new Thread(Singleton.getInstance(), "SigletonThread").start();
    }

    public void run() {

        /*
         * Se uma thread baseada nessa classe já estiver rodando, lança uma
         * exceção.
         */
        if (running) {
            throw new IllegalStateException("A thread já está rodando.");
        }
        running = true;

        /*
         * Isso serve apenas para "segurar" a execução.
         */
        Scanner s = new Scanner(System.in);
        String c = null;
        while (!"exit".equals(c)) {
            c = s.nextLine();
        }

        System.exit(0);
    }

    public static Singleton getInstance() {
        return singleton;
    }

    private Singleton() {}

}

Obrigado!

3 Respostas

M

Cada vez que invocar main vc esta criando uma instancia da JVM e singletons não são capazes de garantir unicidade entre diferentes instancias da JVM.

Para fazer o teste basta colocar um System.out.prinln no construtor. Ele sera invocado quantas vezes vc executar o programa, cada um com seu proprio valor de running, que é false por padrao.

gutostraube

mochuara:
Cada vez que invocar main vc esta criando uma instancia da JVM e singletons não são capazes de garantir unicidade entre diferentes instancias da JVM.

Para fazer o teste basta colocar um System.out.prinln no construtor. Ele sera invocado quantas vezes vc executar o programa, cada um com seu proprio valor de running, que é false por padrao.

mochuara, também imaginei que poderia estar acontecendo isso, porém o debug do Eclipse mostra o mesmo identificador para o objeto nas duas diferentes execuções. Isso que achei estranho. Essa identificação é baseada no hashcode do objeto? Se sim, isso poderia estar gerando o mesmo id mesmo em execuções separadas, em caso contrário, se for um apontador informado pela própria VM, aí é realmente o mesmo objeto.

Vou fazer o teste que você sugeriu e ver o que acontece aqui. Respondo na seqüência com o resultado da experiência.

gutostraube

gutostraube:
mochuara:
Cada vez que invocar main vc esta criando uma instancia da JVM e singletons não são capazes de garantir unicidade entre diferentes instancias da JVM.

Para fazer o teste basta colocar um System.out.prinln no construtor. Ele sera invocado quantas vezes vc executar o programa, cada um com seu proprio valor de running, que é false por padrao.

mochuara, também imaginei que poderia estar acontecendo isso, porém o debug do Eclipse mostra o mesmo identificador para o objeto nas duas diferentes execuções. Isso que achei estranho. Essa identificação é baseada no hashcode do objeto? Se sim, isso poderia estar gerando o mesmo id mesmo em execuções separadas, em caso contrário, se for um apontador informado pela própria VM, aí é realmente o mesmo objeto.

Vou fazer o teste que você sugeriu e ver o que acontece aqui. Respondo na seqüência com o resultado da experiência.

Realmente, mochuara, a classe é instanciada duas vezes. Então o Singleton é único dentro de uma, e apenas um, execução da aplicação, certo?

Obrigado!

Criado 21 de agosto de 2009
Ultima resposta 21 de ago. de 2009
Respostas 3
Participantes 2