Lås och Villkor
I Java är standardsynkronisering baserad på nyckelordet synchronized och inbyggda monitorobjekt. I vissa fall kan dock synchronized vara otillräckligt, särskilt när större flexibilitet i trådhantering krävs.
Allmän beskrivning
Gränssnitten Lock och Condition, introducerade i paketet java.util.concurrent.locks, tillhandahåller avancerade möjligheter för trådhantering.
I denna bild kan du se att första tråden tar låset med hjälp av metoden lock(), och vid detta tillfälle kan en annan tråd inte ta samma lås. Så snart all kod inuti låset har körts, kommer den att anropa metoden unlock() och släppa låset. Först därefter kan andra tråden ta låset.
Skillnad
Skillnaden mellan dessa två gränssnitt är att Lock-implementationer är ett högnivåalternativ till synchronized block, och Condition-gränssnittets implementationer är ett alternativ till metoderna notify()/wait(). Båda dessa gränssnitt ingår i paketet java.util.concurrent.locks.
Exempel från verkliga livet
Föreställ dig att du hanterar en kö för registrering till ett evenemang. För att förhindra överbelastning och säkerställa korrekt platsfördelning behöver du använda blockeringsmekanismer och villkor för att hålla nya registreringar väntande tills en ledig plats blir tillgänglig.
ReentrantLock-klassen
ReentrantLock klassen från paketet java.util.concurrent.locks är en implementering av Lock gränssnittet. Den tillhandahåller funktionalitet för explicit hantering av lås.
De viktigaste metoderna i ReentrantLock:
lock(): Tar ett lås;unlock(): Släpper låset;tryLock(): Försöker ta låset och returnerar true om det lyckas;tryLock(long timeout, TimeUnit unit): Försöker ta låset under angiven tid;newCondition(): Skapar ett villkor för det aktuellaLock.
Main.java
12345678910111213141516171819202122232425262728293031package com.example; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Main { // Creating a ReentrantLock object private final Lock lock = new ReentrantLock(); private int count = 0; // Method to increment the `count` variable public void increment() { lock.lock(); // Acquiring the `lock` try { count++; System.out.println("Count incremented to: " + count); } finally { lock.unlock(); // Releasing the `lock` } } public static void main(String[] args) { Main example = new Main(); // Runnable task to call the increment method Runnable task = example::increment; // Starting multiple threads to execute the task for (int i = 0; i < 5; i++) { new Thread(task).start(); } } }
Som du kan se, i metoden increment() använder vi låsning med Lock. När en tråd går in i metoden tar den låset med lock.lock() och utför sedan koden, och i finally-blocket släpper vi låset med lock.unlock() så att andra trådar kan komma in.
Vi släpper låset i finally-blocket av en anledning, nämligen att detta block nästan alltid körs, även vid undantag, förutom när vi avslutar programmet.
Condition-gränssnitt
Vi kan endast skapa ett Condition med koppling till en specifik Lock-implementation. Av denna anledning kommer Condition-metoderna endast att påverka låsningen för just den aktuella Lock-implementationen.
Main.java
12private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition();
De viktigaste metoderna för Condition:
await(): Väntar på en signal från en annan tråd;signal(): Låser upp en tråd som väntar på ett villkor;signalAll(): Låser upp alla trådar som väntar på villkoret.
Main.java
12345678910111213141516private final ReentrantLock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private boolean ready = false; public void waitForCondition() throws InterruptedException { lock.lock(); // Acquire the `lock` try { while (!ready) { // Check if the condition is not met System.out.println("Waiting..."); // Print a waiting message condition.await(); // Wait for the condition to be signaled } System.out.println("Condition met!"); // Print a message when the condition is met } finally { lock.unlock(); // Release the `lock` } }
waitForCondition()-metoden blockerar tråden tills variabeln ready blir true, vilket signalerar att villkoret har uppfyllts. När villkoret är uppfyllt fortsätter tråden att köra och visar meddelandet "Condition met!"
När await()-metoden anropas pausas tråden och släpper även låset som den har tagit. När tråden vaknar, ska den ta låset igen och först då börjar den att exekvera!
Kodexempel
Nu ska vi titta på ett exempel på hur man använder ReentrantLock och Condition för att hantera registrering till ett evenemang:
Ett kort klipp från videon
Låsning med ReentrantLock: Metoden register() tar låset med lock.lock() för att förhindra att flera trådar kör koden samtidigt.
Villkor med Condition: Om det inte finns några lediga platser anropar tråden spaceAvailable.await() för att vänta tills plats blir tillgänglig.
Frigör lås: När en tråd har frigjort plats med metoden cancel(), anropar den spaceAvailable.signalAll() för att notifiera alla väntande trådar.
Undantagshantering: Användning av try-finally-block säkerställer att låset frigörs även om ett undantag uppstår.
Användningen av Lock och Condition i Java möjliggör mer flexibel kontroll över trådar och synkronisering än den traditionella synchronized-mekanismen. Detta är särskilt användbart i komplexa scenarier där mer exakt kontroll över trådar och väntetillstånd krävs.
Tack för dina kommentarer!
Fråga AI
Fråga AI
Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal
Can you explain the main differences between Lock and Condition in Java?
How does ReentrantLock improve thread management compared to synchronized blocks?
Can you provide a simple example of using Condition with ReentrantLock?
Awesome!
Completion rate improved to 3.33
Lås och Villkor
Svep för att visa menyn
I Java är standardsynkronisering baserad på nyckelordet synchronized och inbyggda monitorobjekt. I vissa fall kan dock synchronized vara otillräckligt, särskilt när större flexibilitet i trådhantering krävs.
Allmän beskrivning
Gränssnitten Lock och Condition, introducerade i paketet java.util.concurrent.locks, tillhandahåller avancerade möjligheter för trådhantering.
I denna bild kan du se att första tråden tar låset med hjälp av metoden lock(), och vid detta tillfälle kan en annan tråd inte ta samma lås. Så snart all kod inuti låset har körts, kommer den att anropa metoden unlock() och släppa låset. Först därefter kan andra tråden ta låset.
Skillnad
Skillnaden mellan dessa två gränssnitt är att Lock-implementationer är ett högnivåalternativ till synchronized block, och Condition-gränssnittets implementationer är ett alternativ till metoderna notify()/wait(). Båda dessa gränssnitt ingår i paketet java.util.concurrent.locks.
Exempel från verkliga livet
Föreställ dig att du hanterar en kö för registrering till ett evenemang. För att förhindra överbelastning och säkerställa korrekt platsfördelning behöver du använda blockeringsmekanismer och villkor för att hålla nya registreringar väntande tills en ledig plats blir tillgänglig.
ReentrantLock-klassen
ReentrantLock klassen från paketet java.util.concurrent.locks är en implementering av Lock gränssnittet. Den tillhandahåller funktionalitet för explicit hantering av lås.
De viktigaste metoderna i ReentrantLock:
lock(): Tar ett lås;unlock(): Släpper låset;tryLock(): Försöker ta låset och returnerar true om det lyckas;tryLock(long timeout, TimeUnit unit): Försöker ta låset under angiven tid;newCondition(): Skapar ett villkor för det aktuellaLock.
Main.java
12345678910111213141516171819202122232425262728293031package com.example; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Main { // Creating a ReentrantLock object private final Lock lock = new ReentrantLock(); private int count = 0; // Method to increment the `count` variable public void increment() { lock.lock(); // Acquiring the `lock` try { count++; System.out.println("Count incremented to: " + count); } finally { lock.unlock(); // Releasing the `lock` } } public static void main(String[] args) { Main example = new Main(); // Runnable task to call the increment method Runnable task = example::increment; // Starting multiple threads to execute the task for (int i = 0; i < 5; i++) { new Thread(task).start(); } } }
Som du kan se, i metoden increment() använder vi låsning med Lock. När en tråd går in i metoden tar den låset med lock.lock() och utför sedan koden, och i finally-blocket släpper vi låset med lock.unlock() så att andra trådar kan komma in.
Vi släpper låset i finally-blocket av en anledning, nämligen att detta block nästan alltid körs, även vid undantag, förutom när vi avslutar programmet.
Condition-gränssnitt
Vi kan endast skapa ett Condition med koppling till en specifik Lock-implementation. Av denna anledning kommer Condition-metoderna endast att påverka låsningen för just den aktuella Lock-implementationen.
Main.java
12private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition();
De viktigaste metoderna för Condition:
await(): Väntar på en signal från en annan tråd;signal(): Låser upp en tråd som väntar på ett villkor;signalAll(): Låser upp alla trådar som väntar på villkoret.
Main.java
12345678910111213141516private final ReentrantLock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private boolean ready = false; public void waitForCondition() throws InterruptedException { lock.lock(); // Acquire the `lock` try { while (!ready) { // Check if the condition is not met System.out.println("Waiting..."); // Print a waiting message condition.await(); // Wait for the condition to be signaled } System.out.println("Condition met!"); // Print a message when the condition is met } finally { lock.unlock(); // Release the `lock` } }
waitForCondition()-metoden blockerar tråden tills variabeln ready blir true, vilket signalerar att villkoret har uppfyllts. När villkoret är uppfyllt fortsätter tråden att köra och visar meddelandet "Condition met!"
När await()-metoden anropas pausas tråden och släpper även låset som den har tagit. När tråden vaknar, ska den ta låset igen och först då börjar den att exekvera!
Kodexempel
Nu ska vi titta på ett exempel på hur man använder ReentrantLock och Condition för att hantera registrering till ett evenemang:
Ett kort klipp från videon
Låsning med ReentrantLock: Metoden register() tar låset med lock.lock() för att förhindra att flera trådar kör koden samtidigt.
Villkor med Condition: Om det inte finns några lediga platser anropar tråden spaceAvailable.await() för att vänta tills plats blir tillgänglig.
Frigör lås: När en tråd har frigjort plats med metoden cancel(), anropar den spaceAvailable.signalAll() för att notifiera alla väntande trådar.
Undantagshantering: Användning av try-finally-block säkerställer att låset frigörs även om ett undantag uppstår.
Användningen av Lock och Condition i Java möjliggör mer flexibel kontroll över trådar och synkronisering än den traditionella synchronized-mekanismen. Detta är särskilt användbart i komplexa scenarier där mer exakt kontroll över trådar och väntetillstånd krävs.
Tack för dina kommentarer!