Descobri uma situação durante a depuração do código, ou seja, quando verifiquei as conexões do memcached, descobri que ele sempre era mantido em cerca de 100. Claro, isso parece não ser problema, pois o memcached tem 1024 conexões por padrão. Mas o que estou pensando é por que existem cerca de 100. Como meu memcachedclient é gerado no modo singleton, defini uma classe memcachedClientFactory.
privado MemcachedClientFactory(){
}
private MemcachedClientFactory(MemcachedConnectionBuilder memcachedConnectionBuilder, servidores String){
this.memcachedConnectionBuilder= memcachedConnectionBuilder;
this.servers=servidores;
}
public static MemcachedClient createClient(){
if(memcachedClient==nulo){
this.memcahcedClien=new MemcachedClient(memcachedConnectionBuilder.build(),AddrUtil.get(servidores));
}
retorne este.memcahcedClient;
}
}
}
Voltando à pergunta original, por que existem mais de 100 conexões?
O método de escrita acima pode realmente garantir que apenas uma conexão será gerada? Obviamente não, por quê? Simultaneidade multi-thread! O problema está aqui: quando vários threads entram no método createClient() ao mesmo tempo e todos decidem que memcachedClient é nulo, várias conexões são geradas. Ha, o problema foi encontrado.
melhorar:
Tudo bem, a mudança é muito simples. Não há problema com o programa e é garantido que existe apenas uma conexão.
Mas deixando esse problema de lado, podemos continuar a pensar profundamente sobre como resolver o problema de simultaneidade no modo singleton.
Deixe-me resumir, existem aproximadamente três maneiras de resolver o problema de simultaneidade no modo singleton:
1. Não use instanciação atrasada, mas use instanciação antecipada.
Ou seja, o programa é reescrito como:
public static Singleton getInstance(){
instância de retorno;
}
}
Ao fazer isso, o jvm cria a instância imediatamente ao carregar a classe, então a premissa disso é que o fardo de criar a instância não é grande, não penso muito no desempenho e confirmamos que a instância definitivamente ser usado. Na verdade, meu código anterior também pode ser usado desta forma:
privado MemcachedClientFactory(){
}
private MemcachedClientFactory(MemcachedConnectionBuilder memcachedConnectionBuilder, servidores String){
this.memcachedConnectionBuilder= memcachedConnectionBuilder;
this.servers=servidores;
}
public static MemcachedClient createClient(){
retorne este.memcahcedClient;
}
}
}
Porém, parece que não há problema, mas há um perigo oculto, ou seja, uma vez que alguém acidentalmente chame o método memcachedClient.shutdown(), todo o programa não será capaz de gerar um novo memcachedClient. Claro que este é um caso extremo, mas por uma questão de robustez do código, pode ser alterado para:
2. Basta usar a palavra-chave sincronizada.
Fazer isso pode garantir problemas de sincronização, mas sabemos que a sobrecarga do uso de sincronizado é muito alta e afetará seriamente o desempenho, então a premissa de usar isso é que você confirme que não chamará esse método com frequência, ou que a sobrecarga de criação esta instância não será grande. Se pode ser melhorado, veja abaixo.
3. Use "bloqueio de verificação dupla" e use sincronização em getInstance
Singleton privado(){};
public static Singleton getInstance(){
if(instância==nulo){
sincronizado (Singleton.class){
if(instância==nulo){
instância=novo Singleton();
}
}
}
instância de retorno;
}
}