Топ-100ReentrantLock - гибкая альтернатива synchronized - CodOrbits
LogoCodOrbits

Раздел: Многопоточность

В этом разделе вы узнаете, как использовать многопоточность в Java для повышения производительности и параллельной обработки.

Все разделы
Иконка Многопоточность

ReentrantLock – гибкая альтернатива synchronized

Last updated: 6 мая 2025 г.

ReentrantLock ведет себя как synchronized, но есть некоторые отличия.

Мы помним, что synchronized блочит цельный кусок кода, то есть synchronized, это цельный метод, который не может быть выполняем параллельно несколькими потоками.

ReentrantLock же хоть и ведет себя как synchronized, но он блочит не цельный метод как это делает synchronized, а может залочить вообще любой кусок кода программы и не важно где начало этого куска а где конец.

То есть если synchronized лочит для других потоков цельный метод то ReentrantLock например может залочить для других потоков часть одного метода и часть другого метода.

Лучше пояснить на примере.

Пример программы:

1import java.io.*;
2import java.util.*;
3import java.util.concurrent.locks.Lock;
4import java.util.concurrent.locks.ReentrantLock;
5
6public class ReentrantLockExample {
7    public static void main(String[] args) {
8        CommonResource commonResource = new CommonResource(); //объект ресурса
9        for (int i = 1; i < 6; i++) {
10            //запускаем 5 потоков передаем в каждый
11            //из них ресурс общий для потоков
12            Thread t = new Thread(new CountThread(commonResource));
13            t.setName("Thread " + i);
14            t.start();
15        }
16    }
17}
18
19class CommonResource {
20    int x;
21    Lock lock = new ReentrantLock();
22    void increment() {
23        //Заблокируем кусок кода, который состоит
24        //из части метода increment и части метода
25        //increment1. То есть очевидно, что это не
26        //цельный кусок кода, а из ранных частей нашего
27        //класса. При synchronized блокируется весь код,
28        //который содержится в методе от первой строки
29        //в нем до последней. Здесь же достаем часть
30        //метода increment, которая после lock.lock()
31        //и часть метода increment1, которая до lock.unlock(), склеиваем эти две части и
32        //блокируем этот склеиный кусок кода как цельный.
33        //То есть очевидно, что все что было в методе increment до вызова lock.lock()
34        //(хотя я данном случае, как видим, там ничего нет) не блокируется, блокируется кусок
35        //посреди метода, а не на весь метод.
36        lock.lock();
37        x=1;
38        for (int i = 1; i < 5; i++) {
39            System.out.printf("%s %d \n", Thread.currentThread().getName(), x);
40            x++;
41            try {
42                Thread.sleep(300);
43            } catch (InterruptedException e) {}
44        }
45        lock.unlock();
46    }
47    void increment1(){
48        x=1;
49        for (int i = 1; i < 5; i++){
50            System.out.printf("%s %d \n",
51                Thread.currentThread().getName(), x);
52            x++;
53            try{
54                Thread.sleep(300);
55            }
56            catch(InterruptedException e){}
57        }
58        lock.unlock(); //разблокируем кусок кода
59        //объекта CommonResource который был
60        //заблокирован в другом методе объекта.
61        //то есть в отличии от synchronized
62        //можно залочить и разлочить
63        //НЕЦЕЛЫЙ кусок кода объекта, то есть
64        //в разных частях объекта.
65    }
66}
67
68class CountThread implements Runnable{
69    CommonResource res;
70    CountThread(CommonResource res){
71        this.res=res;
72    }
73    public void run(){
74        //Лочиться в методе increment
75        res.increment();
76        //Разлочивается в методе increment1
77        res.increment1();
78        //то есть как уже говорилось лок
79        //и разлок нецельного куска
80        //кода в любом месте объекта
81    }
82}

Вывод:

Видим, 5 потоков выполняются по очереди.

Также видим, что каждый из 5 потоков выводит 8 значений. То есть оба цикла в объекте попадают в тот самый не цельный кусок кода, который не может быть выполняем параллельно несколькими потоками благодаря Reentrantlock.


Следующие уроки

Ожидание завершения потоков с помощью CountDownLatch

10
мин.

Similar Articles Icon
Divider

CyclicBarrier в Java

10
мин.

Similar Articles Icon
Divider

Корректная остановка потоков с помощью Interrupt

14
мин.

Similar Articles Icon