{"id":383,"date":"2024-05-10T00:07:23","date_gmt":"2024-05-09T23:07:23","guid":{"rendered":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=383"},"modified":"2024-06-05T00:08:57","modified_gmt":"2024-06-04T23:08:57","slug":"die-details-des-reentrantlock-in-java","status":"publish","type":"post","link":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=383","title":{"rendered":"Die Details des ReentrantLock in Java"},"content":{"rendered":"\n<p>Die Synchronisation von Threads ist eine der gr\u00f6\u00dften Herausforderungen in der parallelen Programmierung. In Java bietet das <code>ReentrantLock<\/code> aus dem <code>java.util.concurrent.locks<\/code>-Paket eine flexible und leistungsf\u00e4hige Alternative zur herk\u00f6mmlichen Synchronisation mit dem <code>synchronized<\/code>-Schl\u00fcsselwort. Dieser Artikel beleuchtet die Eigenschaften, Nutzung und Vorteile des <code>ReentrantLock<\/code>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Grundlagen des ReentrantLock<\/h4>\n\n\n\n<p>Ein <code>ReentrantLock<\/code> ist ein Sperrmechanismus (Lock), der von einem Thread mehrmals gesperrt werden kann, ohne dass es zu einem Deadlock kommt. Dies wird durch die Eigenschaft der Wiedereintrittsf\u00e4higkeit erm\u00f6glicht, d.h., der Thread, der die Sperre bereits h\u00e4lt, kann sie erneut erwerben, ohne blockiert zu werden. Dies ist besonders n\u00fctzlich in rekursiven Algorithmen oder verschachtelten Methodenaufrufen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Erstellung und Nutzung<\/h4>\n\n\n\n<p>Um ein <code>ReentrantLock<\/code> zu verwenden, muss zun\u00e4chst eine Instanz des <code>ReentrantLock<\/code>-Objekts erstellt werden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> java.util.concurrent.locks.ReentrantLock;\n\nReentrantLock lock = <span class=\"hljs-keyword\">new<\/span> ReentrantLock();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><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>Ein typisches Anwendungsbeispiel f\u00fcr die Verwendung eines <code>ReentrantLock<\/code> sieht wie folgt aus:<\/p>\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\">SharedResource<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> ReentrantLock lock = <span class=\"hljs-keyword\">new<\/span> ReentrantLock();\n\n    <span class=\"hljs-keyword\">public<\/span> void safeMethod() {\n        lock.lock();\n        <span class=\"hljs-keyword\">try<\/span> {\n            <span class=\"hljs-comment\">\/\/ kritischer Abschnitt<\/span>\n            System.out.println(<span class=\"hljs-string\">\"Thread \"<\/span> + Thread.currentThread().getName() + <span class=\"hljs-string\">\" f\u00fchrt sicheren Abschnitt aus.\"<\/span>);\n        } <span class=\"hljs-keyword\">finally<\/span> {\n            lock.unlock();\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>In diesem Beispiel wird die Methode <code>safeMethod<\/code> sicher von mehreren Threads ausgef\u00fchrt. Der <code>lock.lock()<\/code>-Aufruf sperrt den kritischen Abschnitt, und <code>lock.unlock()<\/code> stellt sicher, dass die Sperre wieder freigegeben wird, auch wenn eine Ausnahme auftritt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Vorteile von ReentrantLock gegen\u00fcber synchronized<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Flexibilit\u00e4t<\/strong>: <code>ReentrantLock<\/code> bietet mehr Flexibilit\u00e4t als <code>synchronized<\/code>. Zum Beispiel k\u00f6nnen Sperren versucht werden zu erwerben (<code>tryLock()<\/code>), und es gibt Unterst\u00fctzung f\u00fcr bedingte Variablen (<code>Condition<\/code>).<\/li>\n\n\n\n<li><strong>Unterbrechbarkeit<\/strong>: Mit <code>ReentrantLock<\/code> k\u00f6nnen Threads unterbrochen werden, w\u00e4hrend sie auf eine Sperre warten. Dies ist mit dem <code>synchronized<\/code>-Schl\u00fcsselwort nicht m\u00f6glich.<\/li>\n\n\n\n<li><strong>Zeitgesteuertes Warten<\/strong>: <code>ReentrantLock<\/code> erm\u00f6glicht zeitgesteuertes Warten auf eine Sperre, was bedeutet, dass ein Thread nur eine bestimmte Zeitspanne auf die Sperre warten kann, bevor er aufgibt.<\/li>\n\n\n\n<li><strong>Fairness<\/strong>: <code>ReentrantLock<\/code> unterst\u00fctzt faire Sperren, die Threads in der Reihenfolge ihres Wartens bevorzugen, wodurch Starvation (Verhungern) vermieden wird. Dies wird durch die Angabe eines <code>true<\/code>-Parameters im Konstruktor erreicht: <code>new ReentrantLock(true)<\/code>.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Beispiel f\u00fcr erweiterte Funktionen<\/h4>\n\n\n\n<p>Nachfolgend ein Beispiel, das einige der erweiterten Funktionen von <code>ReentrantLock<\/code> demonstriert:<\/p>\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\">import java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.ReentrantLock;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AdvancedResource<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> ReentrantLock lock = <span class=\"hljs-keyword\">new<\/span> ReentrantLock(<span class=\"hljs-keyword\">true<\/span>);\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> Condition condition = lock.newCondition();\n    <span class=\"hljs-keyword\">private<\/span> int resourceCount = <span class=\"hljs-number\">0<\/span>;\n\n    <span class=\"hljs-keyword\">public<\/span> void produce() throws InterruptedException {\n        lock.lock();\n        <span class=\"hljs-keyword\">try<\/span> {\n            <span class=\"hljs-keyword\">while<\/span> (resourceCount &gt;= <span class=\"hljs-number\">5<\/span>) {\n                condition.await();\n            }\n            resourceCount++;\n            System.out.println(<span class=\"hljs-string\">\"Produziert: \"<\/span> + resourceCount);\n            condition.signalAll();\n        } <span class=\"hljs-keyword\">finally<\/span> {\n            lock.unlock();\n        }\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> void consume() throws InterruptedException {\n        lock.lock();\n        <span class=\"hljs-keyword\">try<\/span> {\n            <span class=\"hljs-keyword\">while<\/span> (resourceCount == <span class=\"hljs-number\">0<\/span>) {\n                condition.await();\n            }\n            resourceCount--;\n            System.out.println(<span class=\"hljs-string\">\"Konsumiert: \"<\/span> + resourceCount);\n            condition.signalAll();\n        } <span class=\"hljs-keyword\">finally<\/span> {\n            lock.unlock();\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>In diesem Beispiel wird eine faire Sperre (<code>new ReentrantLock(true)<\/code>) verwendet, um sicherzustellen, dass Threads in der Reihenfolge ihres Eintreffens bedient werden. Die Methoden <code>produce<\/code> und <code>consume<\/code> verwenden eine Bedingungsvariable (<code>Condition<\/code>), um das Warten und Benachrichtigen von Threads zu steuern, was ein klassisches Produzenten-Konsumenten-Problem l\u00f6st.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">ReentrantLock und Deadlocks<\/h4>\n\n\n\n<p>Obwohl <code>ReentrantLock<\/code> viele Vorteile bietet, besteht weiterhin die Gefahr von Deadlocks, wenn Sperren nicht ordnungsgem\u00e4\u00df verwaltet werden. Es ist wichtig, die Reihenfolge, in der Sperren erworben werden, konsistent zu halten, um zyklische Abh\u00e4ngigkeiten zu vermeiden. Ein Deadlock kann beispielsweise wie folgt entstehen:<\/p>\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\">DeadlockExample<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> ReentrantLock lock1 = <span class=\"hljs-keyword\">new<\/span> ReentrantLock();\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> ReentrantLock lock2 = <span class=\"hljs-keyword\">new<\/span> ReentrantLock();\n\n    <span class=\"hljs-keyword\">public<\/span> void method1() {\n        lock1.lock();\n        <span class=\"hljs-keyword\">try<\/span> {\n            Thread.sleep(<span class=\"hljs-number\">100<\/span>); <span class=\"hljs-comment\">\/\/ Simuliert etwas Arbeit<\/span>\n            lock2.lock();\n            <span class=\"hljs-keyword\">try<\/span> {\n                <span class=\"hljs-comment\">\/\/ kritischer Abschnitt<\/span>\n            } <span class=\"hljs-keyword\">finally<\/span> {\n                lock2.unlock();\n            }\n        } <span class=\"hljs-keyword\">catch<\/span> (InterruptedException e) {\n            e.printStackTrace();\n        } <span class=\"hljs-keyword\">finally<\/span> {\n            lock1.unlock();\n        }\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> void method2() {\n        lock2.lock();\n        <span class=\"hljs-keyword\">try<\/span> {\n            Thread.sleep(<span class=\"hljs-number\">100<\/span>); <span class=\"hljs-comment\">\/\/ Simuliert etwas Arbeit<\/span>\n            lock1.lock();\n            <span class=\"hljs-keyword\">try<\/span> {\n                <span class=\"hljs-comment\">\/\/ kritischer Abschnitt<\/span>\n            } <span class=\"hljs-keyword\">finally<\/span> {\n                lock1.unlock();\n            }\n        } <span class=\"hljs-keyword\">catch<\/span> (InterruptedException e) {\n            e.printStackTrace();\n        } <span class=\"hljs-keyword\">finally<\/span> {\n            lock2.unlock();\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>In diesem Beispiel k\u00f6nnen <code>method1<\/code> und <code>method2<\/code> in einen Deadlock geraten, wenn zwei Threads gleichzeitig aufgerufen werden und jeweils die erste Sperre des anderen Threads halten, was zu einer zyklischen Abh\u00e4ngigkeit f\u00fchrt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Performance und Overhead<\/h4>\n\n\n\n<p>Im Vergleich zu <code>synchronized<\/code> ist die Verwendung von <code>ReentrantLock<\/code> tendenziell etwas langsamer aufgrund des h\u00f6heren Overheads, den es mit sich bringt. Dieser Overhead resultiert aus den zus\u00e4tzlichen Funktionen, die <code>ReentrantLock<\/code> bietet, wie z.B. Zeit\u00fcberschreitungen und Unterbrechbarkeit. Allerdings \u00fcberwiegen in vielen Anwendungen die Vorteile dieser zus\u00e4tzlichen Flexibilit\u00e4t und Kontrollm\u00f6glichkeiten den Performanceverlust.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Fazit<\/h4>\n\n\n\n<p><code>ReentrantLock<\/code> ist ein m\u00e4chtiges Werkzeug in der Java-Synchronisationsbibliothek. Es bietet eine Reihe von Vorteilen gegen\u00fcber dem herk\u00f6mmlichen <code>synchronized<\/code>-Schl\u00fcsselwort, einschlie\u00dflich erweiterter Flexibilit\u00e4t, besserer Unterbrechungsf\u00e4higkeit und Unterst\u00fctzung f\u00fcr bedingte Variablen. Allerdings erfordert die Verwendung von <code>ReentrantLock<\/code> auch ein gr\u00fcndliches Verst\u00e4ndnis von Thread-Synchronisation, um Deadlocks und andere Synchronisationsprobleme zu vermeiden. Entwickler sollten sorgf\u00e4ltig abw\u00e4gen, ob die zus\u00e4tzliche Komplexit\u00e4t und der Overhead von <code>ReentrantLock<\/code> f\u00fcr ihre spezifische Anwendung gerechtfertigt sind.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Die Synchronisation von Threads ist eine der gr\u00f6\u00dften Herausforderungen in der parallelen Programmierung. In Java bietet das ReentrantLock aus dem java.util.concurrent.locks-Paket eine flexible und leistungsf\u00e4hige Alternative zur herk\u00f6mmlichen Synchronisation mit dem synchronized-Schl\u00fcsselwort. Dieser Artikel beleuchtet die Eigenschaften, Nutzung und Vorteile des ReentrantLock. Grundlagen des ReentrantLock Ein ReentrantLock ist ein Sperrmechanismus (Lock), der von einem Thread [&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-383","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\/383","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=383"}],"version-history":[{"count":1,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/383\/revisions"}],"predecessor-version":[{"id":384,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/383\/revisions\/384"}],"wp:attachment":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=383"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=383"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=383"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}