Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > de.comp.lang.java > #13131
| From | Marcel Mueller <news.5.maazl@spamgourmet.org> |
|---|---|
| Newsgroups | de.comp.lang.java |
| Subject | Re: Thread-safe singleton |
| Date | 2017-09-06 23:26 +0200 |
| Organization | MB-NET.NET for Open-News-Network e.V. |
| Message-ID | <oopp69$mq$1@gwaiyur.mb-net.net> (permalink) |
| References | <f1am3bF8aciU1@mid.individual.net> |
On 06.09.17 18.29, Christian H. Kuhn wrote:
> Ich dachte, ich hätte das mit der Thread-Sicherheit inzwischen
> verstanden.
Oh, das ist ein weites Areal. Es würde mich wundern, wenn es überhaupt
jemanden gibt, der das bis zum Ende verstanden hat.
> PMD widerspricht mir.
Wer auch immer das ist.
> final class QFdsbDatabase {
>
> private static volatile Connection connection;
Eine statische Connection, hmm ...
> static Connection getConnection() throws QFdsbException {
>
> if (null == connection) {
> synchronized (connection) {
Das wird nix. Das hatten wir ja schon.
Es darf natürlich nur *ein* Objekt geben, auf das synchronisiert wird.
Und null ist ganz schlecht.
> if (null == connection) {
>
> [... Daten aus ini4j-File, dataSource erstellen ... ]
>
> try (Connection myConnection =
> dataSource.getConnection()) {
Das wird auch nichts, es sei denn es sollen geschlossene Verbindungen
geliefert werden. Die lokale Variable im try muss weg.
> myConnection.setAutoCommit(true);
> connection = myConnection;
> } catch (SQLException e) {
> throw new QFdsbException("Problems while opening
> or closing JDBC Connection to player database",
> e);
> }
Die Exception wird hier immer nur an einen Aufrufer ausgeliefert. Die
anderen öffnen eine neue Verbindung - serialisiert, wenn man das Double
Check richtig implementiert. Das kann bei systematischen Fehlern
ziemlich langsam werden bzw. in eine DOS-Attacke ausarten.
Besser die SQLException speichern und immer wieder ausliefern.
Dabei muss man aber darauf achten, dass die null Bedingung jetzt
entweder auf die Exception oder auf die Connection greifen muss.
Alternativ nimmt man Typ Object und packt mal das eine und mal das
andere rein. Lässt es sich nicht auf Connection casten, muss man halt
throw machen.
> Lazy initialization der statischen Variablen, weil ich die geworfenen
> Exceptions sehen will, sonst hätte ich einen static block genommen.
Das ginge mit eben genannter Semantik (Exception speichern) trotzdem.
> Mit
> einem intitialization-on-demand holder vertage ich das Problem in eine
> Unterklasse.
?
> Double-checked locking sollte funktionieren, PMD behauptet
> das Gegenteil.
Implemetierungsfehler.
Es gibt aber noch eine Untiefe:
die gelieferte Connection ist mit an Sicherheit grenzender
Wahrscheinlichkeit nicht thread-safe. Damit ist die Funktion
getConnection in unsynchronisiertem Kontext praktisch unbrauchbar. Und
selbst synchronisiert müsste nicht nur getConnection synchronisiert
werden, sondern auch alle darüber laufenden Zugriffe.
Wenn aber alles rund um die Benutzung der Connection ohnehin
synchronisiert sein muss, dann braucht man das ganze
Double-Check-Gefuddel auch nicht mehr es wird dann ohnehin serialisiert
gearbeitet.
Wenn hingegen umgekehrt mehrere Threads parallel die DB nutzen sollen,
braucht man mehrere Connections und /kein/ Singleton. Das bedeutet jeder
Thread muss die mit getConnection gelieferte Verbindung mit try/finally
anfordern und freigeben.
Wenn jetzt wiederum nicht gewünscht ist, dass dabei jedes mal eine
/neue/ Verbindung aufgemacht wird, braucht man eine Connection pro
Thread. Das könnte man noch mit Thread Local Storage und Lazy Init lösen
(unsynchronisiert).
Wenn darüber hinaus gewünscht ist, dass sich mehrere Threads Connections
teilen, soweit sie nicht gleichzeitig eine Verbindung brauchen, dann
braucht man einen Connection Pool. Dabei ändert sich die Semantik des
von getConnection gelieferten Objektes so, dass es bei Close() nicht
etwa geschlossen wird, sondern schlicht zurück in den Pool geht.
Der Zugriff auf den Pool muss natürlich synchronisiert werden. Das
bedeutet, getConnection benötigt in jedem Fall ein synchronized. Damit
ist der Double Check ebenfalls hinfällig.
Kurzum, es gibt kein denkbares Szenario, in dem Double-Check hier Sinn
ergibt.
Marcel
Back to de.comp.lang.java | Previous | Next — Previous in thread | Next in thread | Find similar
Thread-safe singleton "Christian H. Kuhn" <qno-news@qno.de> - 2017-09-06 18:29 +0200
Re: Thread-safe singleton Patrick Roemer <sangamon@netcologne.de> - 2017-09-06 21:06 +0200
Re: Thread-safe singleton v_borchert@despammed.com (Volker Borchert) - 2017-09-06 20:02 +0000
Re: Thread-safe singleton Patrick Roemer <sangamon@netcologne.de> - 2017-09-06 23:27 +0200
Re: Thread-safe singleton v_borchert@despammed.com (Volker Borchert) - 2017-09-07 16:45 +0000
Re: Thread-safe singleton "Christian H. Kuhn" <qno-news@qno.de> - 2017-09-11 01:08 +0200
Re: Thread-safe singleton Patrick Roemer <sangamon@netcologne.de> - 2017-09-11 18:14 +0200
Re: Thread-safe singleton Marcel Mueller <news.5.maazl@spamgourmet.org> - 2017-09-06 23:26 +0200
Re: Thread-safe singleton Claus Reibenstein <4spamersonly@kabelmail.de> - 2017-09-10 13:52 +0200
csiph-web