Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lära Lås och Villkor | Hög-Nivå Synkroniseringsmekanismer
Quizzes & Challenges
Quizzes
Challenges
/
Multitrådning i Java

bookLås och Villkor

I Java är standard­synkronisering 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ög­nivå­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 aktuella Lock.
Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031
package 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

Main.java

copy
12
private 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

Main.java

copy
12345678910111213141516
private 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!"

Note
Notera

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.

Note
Notering

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.

Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 3. Kapitel 1

Fråga AI

expand

Fråga AI

ChatGPT

Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal

Suggested prompts:

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

bookLås och Villkor

Svep för att visa menyn

I Java är standard­synkronisering 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ög­nivå­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 aktuella Lock.
Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031
package 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

Main.java

copy
12
private 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

Main.java

copy
12345678910111213141516
private 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!"

Note
Notera

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.

Note
Notering

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.

Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 3. Kapitel 1
some-alt