Singleton

28 respostas
J

Tenho uma classe que lê meu arquivo.properties e utilizei o patterns Singleton porém deparei em um problema:

public class Arquivo{
   private static Arquivo arquivo;
   private Properties prop;
   
   public static Arquivo getInstance(){
        if(arquivo==null){
               arquivo=new Arquivo();
         }
      return arquivo;
   }

   public String getProperty(String texto){
       return prop.getProperty(texto);
   }

}

o seguinte eu preciso colocar a palavra “syncronized”

no metodo "getInstance()"
ou
no metodo “getProperty(String texto)”.

ou nos dois metodos?

pois só irá existir um objeto em memoria e todos irão compartilhar o mesmo endereço de memoria. onde devo colocar a palavra “syncronized” ou não precisa?

28 Respostas

S

O Singleton é usado para ter certeza que apenas uma instancia vai estar em memoria, a palavra-chave synchronized nos assegura que o método vai ser executado por apenas uma thread de cada vez, então a palavra-chave synchronized entra no método getInstance( ), para você ter certeza que vai ter apenas uma instancia do objeto mesmo se duas threads tentarem criar a instancia ao mesmo tempo.

pcalcado

Acho que o que ele quer limitar o acesso à é o método getProperties(), logo este método deveria ser sincronizado.

Sincronizar o método getInstance() vai fazer com que cada um dos clientes desta classe obtenha a instância, e não necessariamente vai instanciar a classe. E mesmo que isntanciasse se pudessem ser instanciados inúmeros clientes ele não seria um Singelton.

Assim, duas classes pdoeriam obter a instância em paralelo, uma após a outra, e continuar acessando getProperties() em paralelo.

O ponto é: String são imutáveis, por que raios você precisaria sincronizar mesmo este método?

[]s

danieldestro

Coloque o synchronized no método getInstance().

J

Se o singleton eu vou ter um objeto em memoria…então vou acessar o mesmo toda vez que chamar o singleton…o problema está ai…
se eu for pegar o valor da chave passado com parametro no properties e outro acessar ao mesmo tempo para pegar outro valor de uma outra chave…o resultado vai vim inconsistente.

ex:

chave.um = RATO
chave.dois = GATO

se os dois acessarem o properties ao mesmo tempo como vou saber qual valor vai ser retornado para cada metodo?

A pergunta é: precisa usar “syncronized” em que metodo ou não?

danieldestro

Aí você já está confundindo tudo.
Neste caso não tem problema.

Cada thread vai rodar um método de modo separado. A não ser que dentro do método sejam alterados atributos do método, o que não é o seu caso.

pcalcado

Êpa, peraê!!

Multithreading não significa que a classe vai retornar resutlatos inconsistentes deste jeito. Sincronização é uma primitiva de IPC para evitar Race Conditions, se você está lendo dois dados imutáveis, pode ter certeza qeu seu objeto vai retornar o resultado. O problema é se alguma outra thread alterar o valor que ele está lendo, aí você tem inconsistência.

[]s

J

Vou esclarecer melhor:

tenho todos os meus sql em um arquivo properties. e tem uma classe utilizando o padrão singleton para ler o arquivo no disco rigido uma só vez. agora me expliquem qual metodo preciso syncronizar o “getInstance()” ou o “getProperty(String chave)”.

ou nenhum dos dois e porque?

valeu pessoal

pcalcado

Nenhum dos dois, porque nenhum dos dois possui uma área crítica, não alteram nada.

[]s

C

Bom, acho q vc deve usar synchronized em
getInstance(), pois imagine só se uma thread é paralizada após a comparação:

e antes de executar:

Aí pode ser q vem outra thread pegar uma instancia, onde arquivo ainda é null…
Resultado : vc ficaria com 2 instancias…

pcalcado

Que tal:

public class Arquivo{
   private static Arquivo arquivo=new Arquivo();
   private Properties prop;
   
   public static Arquivo getInstance(){
      return arquivo;
   }

   public String getProperty(String texto){
       return prop.getProperty(texto);
   }

}

[]s

Rafael_Steil

Basta voce NAO fazer isso:

public static Arquivo getInstance(){
        if(arquivo==null){
               arquivo=new Arquivo();
         }
      return arquivo;
   }

eh mais facil e seguro iniciar o membro no momento da declaracao:

private static Arquivo arquivo = new Arquivo();

public static Arquivo getInstance() {
    return arquivo;
}

Rafael
[editado]postei no mesmo momento em que o shoes :mrgreen:[/editado]

pcalcado

:slight_smile:

Complementando

[]s

J

Rafael se eu fizer isso ele vai ler o arquivo do disco rigido de novo, pois:

no meu construtor tenho:
public Arquivo(){
       prop =new Properties("caminho do arquivo.properties);

}

estou certo?

acho que até seria melhor eu usar a classe ResouceBundle para ler o arquivo?

o que vcs acham?

Rafael_Steil

Como ler 2x? se voce chamar o new Arquivo() uma unica vez, o properities soh vai ser lido … uma vez… nao?..

O Properties eh legal.

Rafael

pcalcado

Seu atributo não era estático?

pcalcado

Pô, Rafael, acho melhor colocar o post em synchronized… :lol:

[]s

cv1

So pra lembrar que Singletons sao uma pessima ideia.

Eis o porque: https://www.guj.com.br/forum/viewtopic.php?t=14615

danieldestro

faça:

private Arquivo() { }

J

Rafael vc poderia me dizer a diferença de Properties e ResourceBundle.

em termos de performance e etc.

muito grato,

J

CV a unica maneira de ler um arquivo uma unica vez é usando singleton. ou existe outra solução?

valeu

danieldestro

Properties é um java.util.Hashtable. Muito provavelmente ResourceBundle utilize Hashtable também.

Mas no seu caso, faz mais sentido utilizar Properties.

Rafael_Steil

“j2ee”:
CV a unica maneira de ler um arquivo uma unica vez é usando singleton. ou existe outra solução?

valeu

voce pode fazer ifs(), pode verificar se o objeto eh nulo, pode… ha milhares de maneiras. O lance do singleton no caso seria para carregar uma unica fez e deixar em memoria, o que caracteriza uma necessidade como "… eu nao preciso dar load() nesse arquivo toda vez… ".

Rafael

J

Caro Rafael,

vc poderia postar um exemplo de codigo para eu substituir o singleton?

muito grato pelas respostas, varias respostas em poucos minutos! :lol:

cv1

No seu caso, voce nao precisa de um Singleton, voce precisa de uma variavel estatica… :wink:

J
public final class Arquivo {
	private static Arquivo query=new Arquivo();
	//private Properties prop;
	private ResourceBundle rb;
	private static final String SQL ="config.sql";
	
	public Query(){
		
	    rb=ResourceBundle.getBundle(SQL);
	    
	    //this.prop=new Properties();
	         //this.prop.load(this.getClass().getClassLoader().getResourceAsStream(nomeArquivo));
	
	}
 }

e no quando quiser usar Arquivo a=new Arquivo();

é isso?

valeu

danieldestro

:?: :?: :?: :?

J

desse jeito ele ler varias vezes…! testei aqui!

helpppppppp!

cv1

Cara,

public final class MyProperties {
   private static final String SQL ="config.sql";
   private static Properties properties = new Properties(MyProperties.class.getClassLoader().getResourceAsStream(SQL));
   
   public static Properties getProperties() {
      return properties;   
   }
}

Era soh isso ;)

Criado 25 de agosto de 2004
Ultima resposta 25 de ago. de 2004
Respostas 28
Participantes 7