Descubrí una situación durante la depuración del código, es decir, cuando verifiqué las conexiones de Memcached, descubrí que siempre se mantenía en aproximadamente 100. Por supuesto, esto parece no ser un problema, porque Memcached tiene 1024 conexiones de forma predeterminada. Pero lo que estoy pensando es por qué hay aproximadamente 100. Debido a que mi memcachedclient se genera en modo singleton, definí una clase memcachedClientFactory. El código principal es el siguiente:
MemcachedClientFactory privado(){
}
MemcachedClientFactory privado (MemcachedConnectionBuilder memcachedConnectionBuilder, servidores de cadenas){
this.memcachedConnectionBuilder= memcachedConnectionBuilder;
this.servers=servidores;
}
MemcachedClient público estático createClient(){
si(memcachedClient==null){
this.memcahcedClien= new MemcachedClient(memcachedConnectionBuilder.build(),AddrUtil.get(servidores));
}
devolver this.memcahcedClient;
}
}
}
Volviendo a la pregunta original, ¿por qué hay más de 100 conexiones?
¿Puede el método de escritura anterior realmente garantizar que solo se generará una conexión? Obviamente no, ¿por qué? ¡Simultaneidad multiproceso! El problema radica aquí. Cuando varios subprocesos ingresan al método createClient () al mismo tiempo y todos deciden que memcachedClient es nulo, se generan múltiples conexiones. Ja, se encontró el problema.
mejorar:
Esto está bien, el cambio es muy sencillo. No hay ningún problema con el programa y se garantiza que solo hay una conexión.
Pero dejando de lado este problema, podemos seguir pensando profundamente en cómo resolver el problema de concurrencia en modo singleton.
Permítanme resumir: hay aproximadamente tres formas de resolver el problema de concurrencia en modo singleton:
1. No utilice la creación de instancias retrasadas, sino la creación de instancias tempranas.
Es decir, el programa se reescribe como:
getInstance público estático Singleton(){
instancia de devolución;
}
}
Al hacer esto, jvm crea la instancia inmediatamente al cargar la clase, por lo que la premisa de esto es que la carga de crear la instancia no es grande, no pienso demasiado en el rendimiento y confirmamos que la instancia definitivamente ser utilizado. De hecho, mi código anterior también se puede utilizar de esta manera:
MemcachedClientFactory privado(){
}
MemcachedClientFactory privado (MemcachedConnectionBuilder memcachedConnectionBuilder, servidores de cadenas){
this.memcachedConnectionBuilder= memcachedConnectionBuilder;
this.servers=servidores;
}
MemcachedClient público estático createClient(){
devolver this.memcahcedClient;
}
}
}
Sin embargo, parece que no hay ningún problema, pero existe un peligro oculto, es decir, una vez que alguien llama accidentalmente al método memcachedClient.shutdown (), todo el programa no podrá generar un nuevo memcachedClient. Por supuesto, este es un caso extremo, pero en aras de la solidez del código, se puede cambiar a:
2. Simplemente use la palabra clave sincronizada.
Hacer esto puede garantizar problemas de sincronización, pero sabemos que la sobrecarga de usar sincronizado es muy alta y afectará seriamente el rendimiento, por lo que la premisa de usar esto es que usted confirma que no llamará a este método con frecuencia o que la sobrecarga de crear Esta instancia no será especial. Si se puede mejorar, consulte a continuación.
3. Utilice "bloqueo de doble verificación" y utilice la sincronización en getInstance
singleton privado(){};
getInstance público estático Singleton(){
si (instancia == nulo) {
sincronizado (Singleton.class){
si (instancia == nulo) {
instancia=nuevo Singleton();
}
}
}
instancia de devolución;
}
}