Друкарня від WE.UA

Java. ReadWriteLock

1. Основи ReadWriteLock

Основна ідея ReadWriteLock полягає в тому, що він надає два локи:

  • Лок на читання: Дозволяє декільком потокам одночасно читати ресурс, але блокується, якщо будь-який потік має лок на запис. Призначено для ситуацій, коли читання здійснюється частіше, ніж запис.

  • Лок на запис: Цей лок може мати лише один потік одночасно(exclusive). Якщо потік має лок на запис, жоден інший потік (чи це читання, чи запис) не може отримати лок на читання або запис. Це гарантує ексклюзивний доступ до ресурсу для потоку, який записує.

2. Внутрішня структура ReentrantReadWriteLock

a. Стан:

  • Внутрішній стан ReentrantReadWriteLock підтримується як єдина змінна типу int. Це число розділено на дві частини:

    • Верхні 16 бітів для кількості локів на читання (всіми потоками).

    • Нижні 16 бітів для кількості локів на запис (лічильник повторного входження для потоку запису).

b. Лічильник утримань (Holding count):

  • Коли потік отримує лок на запис кілька разів (повторно), нижні 16 бітів (частина запису) збільшуються.

  • Коли потік отримує лок на читання, верхні 16 бітів збільшуються. Але є нюанс: так як декілька потоків можуть мати лок на читання одночасно, ReadWriteLock повинен відстежувати, скільки локів на читання має кожен потік. Для цього використовується ThreadLocalHoldCounter, яка відображає потоки на їхні лічильники. Верхні 16 бітів представляють суму всіх цих лічильників.

Приклад. Потік займає лок на читання:
Read count:  0000 0000 0000 0001
Write count: 0000 0000 0000 0000

c. Взяття і відпускання локу (Acquiring/releasing):

  • Коли потік намагається отримати лок на читання, він перевіряє, чи має інший потік лок на запис (перевіряючи нижні 16 бітів). Якщо ні, він збільшує лічильник локів на читання.

  • Коли потік намагається отримати лок на запис, він перевіряє лічильники локів на читання та запису. Лок на запис можна отримати, якщо жоден потік не має локу на читання (верхні 16 бітів нульові) і якщо лок на запис не має або має викликаючий потік (повторне отримання).

  • При відпусканні відповідні лічильники зменшуються.

d. Справедливість (Fairness):

  • ReentrantReadWriteLock може працювати в двох режимах: справедливому та несправедливому.

    • У справедливому режимі потоки отримують доступ в порядку, в якому вони хотіли отримати лок. Це досягається за допомогою внутрішньої черги очікування. Це зменшує шанси на голодування потоків, але часто має меншу пропускну спроможність, ніж в несправедливому режимі.

    • У несправедливому режимі є так звана поведінка “вривання“. Якщо потік хоче читати, і є інші очікуючі потоки, але жоден з них не є “письмовим“, він може "вриватися" і отримувати лок еа читання. Це може підвищити продуктивність, але може вводити деяку непередбачуваність у планування потоків.

e. Умови (Condition):

  • Лок на запис (і лише на запис) надає об'єкти Condition, які дозволяють потокам "очікувати" на конкретні умови для їх виконання. Це не підтримується для локів на читання через потенційні дедлоки.

3. Для чого використовувати?

Головною перевагою ReadWriteLock є “покращена паралельність” під час інтенсивних запитів на читання. Дозволяючи кільком потокам читати одночасно, він часто забезпечує кращу продуктивність, ніж синхронізований блок, особливо коли операції запису виконуються не часто.


  • Взяття локу на запис

    public class Main {
        public static void main(String[] args) {
            ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
            Thread thread1 = new MyThread(readWriteLock, "One");
            Thread thread2 = new MyThread(readWriteLock, "Two");
        }
    }
    
    class MyThread extends Thread {
        private final ReadWriteLock readWriteLock;
        public MyThread(ReadWriteLock readWriteLock, String name) {
            setName(name);
            this.readWriteLock = readWriteLock;
            start();
        }
    
        @Override
        public void run() {
            try {
                System.out.println(getName() +": About to acquire the lock");
                readWriteLock.writeLock().lock();
                System.out.println(getName() +": Took the lock. Doing some operations with it");
                while (true);
            } finally {
                readWriteLock.writeLock().unlock();
            }
        }
    }
output
VisualVM. Java process profiling
  • Взяття локу на читання (змінився тільки метод run)

    @Override
    public void run() {
        try {
            System.out.println(getName() +": About to acquire the lock");
            readWriteLock.readLock().lock();
            System.out.println(getName() +": Took the lock. Doing some operations with it");
            while (true);
        } finally {
            readWriteLock.readLock().unlock();
        }
    }

    output
VisualVM. Java process profiling

Статті про вітчизняний бізнес та цікавих людей:

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Oleksandr Klymenko
Oleksandr Klymenko@overpathz we.ua/overpathz

Java Software Engineer

40Довгочити
8.2KПрочитання
98Підписники
На Друкарні з 19 квітня

Більше від автора

  • Java Memory Model ↔ PostgreSQL MVCC: один і той самий фундамент конкурентності

    Java Memory Model та PostgreSQL MVCC/Isolation Levels — це дві відповіді на одне й те саме фундаментальне питання: за яких умов зміна, зроблена одним учасником (потоком / транзакцією), стає видимою для іншого?

    Теми цього довгочиту:

    Java
  • Як виконується SQL-запит

    Сьогодні розберемо, що відбувається з вашим SELECT * FROM users WHERE age > 21 перед тим, як БД поверне вам дані

    Теми цього довгочиту:

    Computer Science

Це також може зацікавити:

  • Еволюція ллмок 2024

    Коротше ото ж всі побігли рік тому терміново робити свої ллмки і бабки збирати під свої єбейші стартапи.

    Публікація містить описи/фото насилля, еротики або іншого чутливого контенту.

    Теми цього довгочиту:

    Llm
  • Про закономірне падіння аутсорсу в Україні

    Новина була про те, що кількість працівників в аутсорсі зрівнялась з кількістю працівників в продуктових конторах по Україні. Особисто я вважаю аутсор Український просто дуже поганим явищем для ринку. Всі ці скрам мастери, ейчари, джиари, і інші беззмістовні галерні форми життя.

    Теми цього довгочиту:

    It
  • BalansyrHDD. Вгамовуємо мікрофрізи та coil whine за допомогою моєї програми

    Моя Java-програмка для стареньких компутерів, що допомагає позбутися мікрофрізів та coil whine (пищання в дроселях HDD).

    Теми цього довгочиту:

    Застосунки Для Windows

Коментарі (0)

Підтримайте автора першим.
Напишіть коментар!

Це також може зацікавити:

  • Еволюція ллмок 2024

    Коротше ото ж всі побігли рік тому терміново робити свої ллмки і бабки збирати під свої єбейші стартапи.

    Публікація містить описи/фото насилля, еротики або іншого чутливого контенту.

    Теми цього довгочиту:

    Llm
  • Про закономірне падіння аутсорсу в Україні

    Новина була про те, що кількість працівників в аутсорсі зрівнялась з кількістю працівників в продуктових конторах по Україні. Особисто я вважаю аутсор Український просто дуже поганим явищем для ринку. Всі ці скрам мастери, ейчари, джиари, і інші беззмістовні галерні форми життя.

    Теми цього довгочиту:

    It
  • BalansyrHDD. Вгамовуємо мікрофрізи та coil whine за допомогою моєї програми

    Моя Java-програмка для стареньких компутерів, що допомагає позбутися мікрофрізів та coil whine (пищання в дроселях HDD).

    Теми цього довгочиту:

    Застосунки Для Windows