{"id":618,"date":"2025-07-25T23:25:28","date_gmt":"2025-07-25T22:25:28","guid":{"rendered":"https:\/\/www.javaeinfacherkl\u00e4rt.de\/?p=618"},"modified":"2025-08-07T23:26:16","modified_gmt":"2025-08-07T22:26:16","slug":"thread-sicheres-singleton-in-java","status":"publish","type":"post","link":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=618","title":{"rendered":"Thread-sicheres Singleton in Java"},"content":{"rendered":"\n<p>Das <strong>Singleton-Muster<\/strong> ist eines der bekanntesten Entwurfsmuster in der objektorientierten Programmierung. Es sorgt daf\u00fcr, dass von einer Klasse <strong>nur genau eine Instanz<\/strong> existiert und bietet einen globalen Zugriffspunkt auf dieses Objekt. In Java kann die Implementierung jedoch schnell problematisch werden, wenn mehrere Threads gleichzeitig auf die Instanz zugreifen \u2013 Stichwort <strong>Thread-Sicherheit<\/strong>. In diesem Artikel betrachten wir verschiedene M\u00f6glichkeiten, wie man ein Singleton in Java <strong>korrekt und thread-sicher<\/strong> implementiert.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Warum \u00fcberhaupt Singleton?<\/strong><\/h2>\n\n\n\n<p>Ein Singleton wird oft eingesetzt, wenn:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Eine <strong>zentrale Steuerinstanz<\/strong> ben\u00f6tigt wird (z.\u202fB. Logger, Konfigurationsmanager, Cache).<\/li>\n\n\n\n<li>Der Zugriff auf <strong>gemeinsame Ressourcen<\/strong> zentral geregelt werden soll.<\/li>\n\n\n\n<li>Eine <strong>gemeinsame Datenbasis<\/strong> innerhalb einer Anwendung verf\u00fcgbar sein soll.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Die Grundform eines Singleton (nicht thread-sicher)<\/strong><\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Singleton<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> Singleton instance;\n\n    <span class=\"hljs-keyword\">private<\/span> Singleton() {\n        <span class=\"hljs-comment\">\/\/ private Konstruktor<\/span>\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> Singleton getInstance() {\n        <span class=\"hljs-keyword\">if<\/span> (instance == <span class=\"hljs-keyword\">null<\/span>) {\n            instance = <span class=\"hljs-keyword\">new<\/span> Singleton();\n        }\n        <span class=\"hljs-keyword\">return<\/span> instance;\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Dieses Beispiel ist <strong>nicht thread-sicher<\/strong>. Wenn zwei Threads gleichzeitig <code>getInstance()<\/code> aufrufen und <code>instance == null<\/code> ist, kann es passieren, dass beide Threads eine neue Instanz erstellen.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Thread-sichere Varianten<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. <strong>Synchronisierte Methode (einfach, aber ineffizient)<\/strong><\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Singleton<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> Singleton instance;\n\n    <span class=\"hljs-keyword\">private<\/span> Singleton() {}\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> synchronized Singleton getInstance() {\n        <span class=\"hljs-keyword\">if<\/span> (instance == <span class=\"hljs-keyword\">null<\/span>) {\n            instance = <span class=\"hljs-keyword\">new<\/span> Singleton();\n        }\n        <span class=\"hljs-keyword\">return<\/span> instance;\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>Vorteile:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Einfach zu verstehen.<\/li>\n\n\n\n<li>Thread-sicher.<\/li>\n<\/ul>\n\n\n\n<p><strong>Nachteile:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Die Synchronisierung verlangsamt den Zugriff \u2013 selbst wenn das Objekt bereits initialisiert ist.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">2. <strong>Double-Checked Locking (effizienter)<\/strong><\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Singleton<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> volatile Singleton instance;\n\n    <span class=\"hljs-keyword\">private<\/span> Singleton() {}\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> Singleton getInstance() {\n        <span class=\"hljs-keyword\">if<\/span> (instance == <span class=\"hljs-keyword\">null<\/span>) {\n            synchronized (Singleton<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>) <\/span>{\n                <span class=\"hljs-keyword\">if<\/span> (instance == <span class=\"hljs-keyword\">null<\/span>) {\n                    instance = <span class=\"hljs-keyword\">new<\/span> Singleton();\n                }\n            }\n        }\n        <span class=\"hljs-keyword\">return<\/span> instance;\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>Was ist hier neu?<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Die Variable ist als <code>volatile<\/code> deklariert, um <strong>Instruktionsreordering<\/strong> zu verhindern.<\/li>\n\n\n\n<li>Zwei Pr\u00fcfungen auf <code>instance == null<\/code>, eine au\u00dferhalb und eine innerhalb des <code>synchronized<\/code>-Blocks \u2013 daher der Name \u201edouble-checked locking\u201c.<\/li>\n<\/ul>\n\n\n\n<p><strong>Vorteile:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Schnell, sobald die Instanz einmal erzeugt wurde.<\/li>\n\n\n\n<li>Thread-sicher ohne unn\u00f6tige Synchronisation.<\/li>\n<\/ul>\n\n\n\n<p><strong>Nachteile:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Etwas komplexer zu verstehen.<\/li>\n\n\n\n<li>Funktioniert erst ab Java 1.5 korrekt (wegen <code>volatile<\/code>).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">3. <strong>Initialisierung-on-Demand-Holder (empfohlene Methode)<\/strong><\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Singleton<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> Singleton() {}\n\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Holder<\/span> <\/span>{\n        <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">final<\/span> Singleton INSTANCE = <span class=\"hljs-keyword\">new<\/span> Singleton();\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> Singleton getInstance() {\n        <span class=\"hljs-keyword\">return<\/span> Holder.INSTANCE;\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>Funktionsweise:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Die Instanz wird in einer <strong>statischen inneren Klasse<\/strong> gehalten.<\/li>\n\n\n\n<li>Die Klasse <code>Holder<\/code> wird <strong>erst geladen<\/strong>, wenn <code>getInstance()<\/code> aufgerufen wird.<\/li>\n\n\n\n<li>Die Java Virtual Machine garantiert, dass die Initialisierung von <code>INSTANCE<\/code> <strong>thread-sicher<\/strong> ist.<\/li>\n<\/ul>\n\n\n\n<p><strong>Vorteile:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Lazy Loading<\/strong> ohne explizite Synchronisierung.<\/li>\n\n\n\n<li>Sehr effizient.<\/li>\n\n\n\n<li>Einfache und elegante L\u00f6sung.<\/li>\n<\/ul>\n\n\n\n<p><strong>Nachteile:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Weniger bekannt; f\u00fcr einige Entwickler schwerer zu durchschauen.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">4. <strong>Enum-Singleton (besonders robust)<\/strong><\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">public<\/span> enum Singleton {\n    INSTANCE;\n\n    <span class=\"hljs-keyword\">public<\/span> void doSomething() {\n        <span class=\"hljs-comment\">\/\/ Methode aufrufen<\/span>\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>Was macht diese L\u00f6sung besonders?<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Enums sind per Definition <strong>thread-sicher<\/strong> und vor <strong>Serialisierungsangriffen<\/strong> gesch\u00fctzt.<\/li>\n\n\n\n<li>Auch bei <strong>Deserialisierung<\/strong> oder <strong>Reflection<\/strong> bleibt das Singleton intakt.<\/li>\n<\/ul>\n\n\n\n<p><strong>Vorteile:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>K\u00fcrzester Code.<\/li>\n\n\n\n<li>Automatisch thread-sicher.<\/li>\n\n\n\n<li>Schutz gegen komplexe Fehlerquellen (z.\u202fB. durch Deserialisierung).<\/li>\n<\/ul>\n\n\n\n<p><strong>Nachteile:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Weniger flexibel (z.\u202fB. keine Vererbung m\u00f6glich).<\/li>\n\n\n\n<li>F\u00fcr viele Entwickler ungewohnt.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Was ist mit Serialisierung?<\/strong><\/h2>\n\n\n\n<p>Ein Problem klassischer Singleton-Implementierungen ist, dass durch <strong>Deserialisierung<\/strong> eine neue Instanz erzeugt werden kann. Um das zu verhindern, sollte man <code>readResolve()<\/code> \u00fcberschreiben:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">private <span class=\"hljs-built_in\">Object<\/span> readResolve() {\n    <span class=\"hljs-keyword\">return<\/span> getInstance();\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Beim Enum-Singleton tritt dieses Problem <strong>nicht auf<\/strong>, da Enums automatisch serialisierungsfest sind.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Zusammenfassung und Empfehlung<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Variante<\/th><th>Thread-sicher<\/th><th>Lazy Loading<\/th><th>Einfachheit<\/th><th>Performance<\/th><\/tr><\/thead><tbody><tr><td>Unsynchronisiert<\/td><td>\u274c<\/td><td>\u2705<\/td><td>\u2705<\/td><td>\u2705<\/td><\/tr><tr><td>Synchronisierte Methode<\/td><td>\u2705<\/td><td>\u2705<\/td><td>\u2705<\/td><td>\u274c<\/td><\/tr><tr><td>Double-Checked Locking<\/td><td>\u2705<\/td><td>\u2705<\/td><td>\u2796<\/td><td>\u2705<\/td><\/tr><tr><td>Static Holder<\/td><td>\u2705<\/td><td>\u2705<\/td><td>\u2705<\/td><td>\u2705<\/td><\/tr><tr><td>Enum<\/td><td>\u2705<\/td><td>\u274c (sofort bei Laden)<\/td><td>\u2705<\/td><td>\u2705<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>Empfehlung:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>F\u00fcr die meisten Anwendungen ist die <strong>Holder-Variante<\/strong> die beste Wahl.<\/li>\n\n\n\n<li>Wenn Robustheit gegen Reflection und Serialisierung wichtig ist, sollte man die <strong>Enum-Variante<\/strong> verwenden.<\/li>\n\n\n\n<li>Die synchronisierte Methode ist nur f\u00fcr einfache, nicht performance-kritische Anwendungen geeignet.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Fazit<\/strong><\/h2>\n\n\n\n<p>Die Implementierung eines Singleton in Java scheint auf den ersten Blick trivial \u2013 doch gerade in <strong>mehrthreadigen Anwendungen<\/strong> kann sie zu unerwarteten Fehlern f\u00fchren. Java bietet mehrere M\u00f6glichkeiten, ein Singleton <strong>thread-sicher<\/strong> zu gestalten, jede mit ihren eigenen Vor- und Nachteilen. Wer Wert auf <strong>Effizienz und Sicherheit<\/strong> legt, sollte entweder das <strong>Initialisierung-on-Demand Holder Pattern<\/strong> oder die <strong>Enum-Variante<\/strong> verwenden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Das Singleton-Muster ist eines der bekanntesten Entwurfsmuster in der objektorientierten Programmierung. Es sorgt daf\u00fcr, dass von einer Klasse nur genau eine Instanz existiert und bietet einen globalen Zugriffspunkt auf dieses Objekt. In Java kann die Implementierung jedoch schnell problematisch werden, wenn mehrere Threads gleichzeitig auf die Instanz zugreifen \u2013 Stichwort Thread-Sicherheit. In diesem Artikel betrachten [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-618","post","type-post","status-publish","format-standard","hentry","category-plain_java"],"_links":{"self":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/618","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=618"}],"version-history":[{"count":1,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/618\/revisions"}],"predecessor-version":[{"id":619,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/618\/revisions\/619"}],"wp:attachment":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=618"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=618"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=618"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}