Ich habe beim Code-Debuggen eine Situation entdeckt, das heißt, als ich die Verbindungen von Memcached überprüfte, stellte ich fest, dass sie immer bei etwa 100 gehalten wurden. Dies scheint natürlich kein Problem zu sein, da Memcached standardmäßig 1024 Verbindungen hat. Aber ich denke darüber nach, warum es ungefähr 100 sind. Da mein memcachedclient im Singleton-Modus generiert wird, habe ich eine memcachedClientFactory-Klasse definiert. Der Hauptcode lautet wie folgt:
private MemcachedClientFactory(){
}
private MemcachedClientFactory(MemcachedConnectionBuilder memcachedConnectionBuilder, String-Server){
this.memcachedConnectionBuilder= memcachedConnectionBuilder;
this.servers=server;
}
öffentlicher statischer MemcachedClient createClient(){
if(memcachedClient==null){
this.memcahcedClien= new MemcachedClient(memcachedConnectionBuilder.build(),AddrUtil.get(servers));
}
return this.memcahcedClient;
}
}
}
Zurück zur ursprünglichen Frage: Warum gibt es mehr als 100 Verbindungen?
Kann die obige Schreibmethode wirklich garantieren, dass nur eine Verbindung generiert wird? Offensichtlich nicht, warum? Multithread-Parallelität! Das Problem liegt hier. Wenn mehrere Threads gleichzeitig die Methode createClient() aufrufen und alle entscheiden, dass memcachedClient null ist, werden mehrere Verbindungen generiert. Ha, das Problem wurde gefunden.
verbessern:
Das ist in Ordnung, die Änderung ist sehr einfach. Es gibt kein Problem mit dem Programm und es ist garantiert, dass nur eine Verbindung besteht.
Wenn wir dieses Problem jedoch beiseite lassen, können wir weiterhin gründlich darüber nachdenken, wie wir das Parallelitätsproblem im Singleton-Modus lösen können.
Lassen Sie mich zusammenfassen: Es gibt ungefähr drei Möglichkeiten, das Problem der Parallelität im Singleton-Modus zu lösen:
1. Verwenden Sie keine verzögerte Instanziierung, sondern eine frühe Instanziierung.
Das heißt, das Programm wird wie folgt umgeschrieben:
öffentliches statisches Singleton getInstance(){
Rückgabeinstanz;
}
}
Dabei erstellt der JVM die Instanz sofort beim Laden der Klasse. Die Voraussetzung dafür ist also, dass die Belastung durch die Erstellung der Instanz nicht groß ist, ich nicht zu viel über die Leistung nachdenke und wir bestätigen, dass die Instanz dies definitiv tun wird verwendet werden. Tatsächlich kann mein vorheriger Code auch auf diese Weise verwendet werden:
private MemcachedClientFactory(){
}
private MemcachedClientFactory(MemcachedConnectionBuilder memcachedConnectionBuilder, String-Server){
this.memcachedConnectionBuilder= memcachedConnectionBuilder;
this.servers=server;
}
öffentlicher statischer MemcachedClient createClient(){
return this.memcahcedClient;
}
}
}
Es scheint jedoch kein Problem zu geben, es besteht jedoch eine versteckte Gefahr: Sobald jemand versehentlich die Methode memcachedClient.shutdown () aufruft, kann das gesamte Programm keinen neuen memcachedClient generieren. Dies ist natürlich ein Extremfall, aber aus Gründen der Code-Robustheit kann er wie folgt geändert werden:
2. Verwenden Sie einfach das synchronisierte Schlüsselwort.
Dies kann zu Synchronisierungsproblemen führen. Wir wissen jedoch, dass der Overhead bei der Verwendung von „synced“ sehr hoch ist und die Leistung erheblich beeinträchtigt. Daher besteht die Voraussetzung für die Verwendung darin, dass Sie bestätigen, dass Sie diese Methode nicht häufig aufrufen oder dass der Overhead beim Erstellen zu hoch ist Dieser Fall wird nichts Besonderes sein. Ob es verbessert werden kann, siehe unten.
3. Verwenden Sie „Double Check Locking“ und verwenden Sie die Synchronisierung in getInstance
private Singleton(){};
öffentliches statisches Singleton getInstance(){
if(instance==null){
synchronisiert (Singleton.class){
if(instance==null){
Instanz=neuer Singleton();
}
}
}
Rückgabeinstanz;
}
}