Mark As Completed Discussion

Locks and Conditions

In concurrent programming, locks and conditions are advanced synchronization mechanisms that provide more flexibility and control over the execution flow of threads.

Locks

Locks are used to control access to shared resources by multiple threads. When a thread wants exclusive access to a shared resource, it acquires the lock associated with that resource. Other threads trying to acquire the same lock will be blocked until the lock is released.

Java provides the java.util.concurrent.locks.Lock interface that defines the basic operations of a lock. One of the commonly used lock implementations is java.util.concurrent.locks.ReentrantLock.

Here's an example of how to use a ReentrantLock to control access to a shared resource:

SNIPPET
1import java.util.concurrent.locks.Lock;
2import java.util.concurrent.locks.ReentrantLock;
3
4public class Main {
5
6    private Lock lock = new ReentrantLock();
7    private int count = 0;
8
9    public void increment() {
10        lock.lock();
11        try {
12            count++;
13        } finally {
14            lock.unlock();
15        }
16    }
17
18    public static void main(String[] args) {
19        Main main = new Main();
20
21        // Create multiple threads
22        for (int i = 0; i < 10; i++) {
23            Thread thread = new Thread(() -> {
24                for (int j = 0; j < 1000; j++) {
25                    main.increment();
26                }
27            });
28            thread.start();
29        }
30
31        try {
32            Thread.sleep(2000);
33        } catch (InterruptedException e) {
34            e.printStackTrace();
35        }
36
37        System.out.println("Count: " + main.count);
38    }
39}

Conditions

Conditions are used to manage the execution flow of threads within a lock. They allow threads to wait until a specific condition is met and to signal other threads when the condition becomes true.

Java provides the java.util.concurrent.locks.Condition interface for working with conditions. Conditions are created from a lock using the newCondition() method.

Here's an example of how to use a condition to coordinate the execution of two threads:

SNIPPET
1import java.util.concurrent.locks.Condition;
2import java.util.concurrent.locks.Lock;
3import java.util.concurrent.locks.ReentrantLock;
4
5public class Main {
6
7    private Lock lock = new ReentrantLock();
8    private Condition condition = lock.newCondition();
9    private boolean isDataReady = false;
10
11    public void producer() throws InterruptedException {
12        lock.lock();
13        try {
14            // Produce data
15            isDataReady = true;
16            // Signal the consumer
17            condition.signal();
18        } finally {
19            lock.unlock();
20        }
21    }
22
23    public void consumer() throws InterruptedException {
24        lock.lock();
25        try {
26            while (!isDataReady) {
27                // Wait for data to be ready
28                condition.await();
29            }
30            // Consume data
31            isDataReady = false;
32        } finally {
33            lock.unlock();
34        }
35    }
36
37    public static void main(String[] args) {
38        Main main = new Main();
39
40        // Create producer thread
41        Thread producerThread = new Thread(() -> {
42            try {
43                Thread.sleep(2000);
44                main.producer();
45            } catch (InterruptedException e) {
46                e.printStackTrace();
47            }
48        });
49
50        // Create consumer thread
51        Thread consumerThread = new Thread(() -> {
52            try {
53                main.consumer();
54            } catch (InterruptedException e) {
55                e.printStackTrace();
56            }
57        });
58
59        producerThread.start();
60        consumerThread.start();
61
62        try {
63            producerThread.join();
64            consumerThread.join();
65        } catch (InterruptedException e) {
66            e.printStackTrace();
67        }
68    }
69}

In this example, the producer thread acquires the lock, produces some data, and signals the consumer thread using the condition's signal() method. The consumer thread waits for the data to be ready by calling the condition's await() method.

By using locks and conditions, you can implement advanced thread synchronization scenarios where precise control over the execution flow is required.

JAVA
OUTPUT
:001 > Cmd/Ctrl-Enter to run, Cmd/Ctrl-/ to comment