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

Java. Чому не можна синхронізуватись на об'єктах-враперах?

Всі знають, що якщо нам потрібно зробити якусь неатомарну операцію, треба засинхронізуватись.
Давайте так і зробимо. Знизу дефолтний приклад інкрементації змінної з декілької потоків.

public class Test {
    public static int counter = 0;
    public static Integer LOCK = Integer.MIN_VALUE;

    public static void increment() {
        // synchronize using lock of wrapper class
        synchronized (LOCK) {
            counter++;
            LOCK++;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        // Runnable which processing increment of LOCK variable
        Runnable runnable = () -> {
            for (int i = 0; i < 1_000_000; i++) {
                increment();
            }
        };
        // starting threads
        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        Thread t3 = new Thread(runnable);
        Thread t4 = new Thread(runnable);
        startAndJoin(t1, t2, t3, t4);
        System.out.println(counter);
    }

    private static void startAndJoin(Thread... threads) throws InterruptedException {
        for (Thread thread : threads) {
            thread.start();
        }
        for (Thread thread : threads) {
            thread.join();
        }
    }
}

Локом буде виступає об’єкт класу Integer.
Результат виконання main методу “2075471”.
А мало бути 4кк, оскільки кожен із 4 потоків накручує по 1кк:

Чому так відбувається?

Перший потік займає монітор, виконує свою логіку, в цей час інший потік який також хотів прокрутити свою логіку натрапив на монітор, який його не пустив і монітор поклав цей потік собі в чергу(*1).
І повідомив про це операційній системі, яка тепер, при виході першого потоку(вона буде за цим слідкувати) має витягнути інший потік(який “чекав в черзі“) і покласти його в іншу чергу яка називається ready queue, яку ж потім запустить на виконання сама ОС згідно свого планувальника.
Але, від об’єкта нічого не залишилось(*2), бо під час інкрементування першим потоком він зник і на його місце прийшов новий об’єкт(а з ним, його монітор, зі своєю чергою очікуючих потоків).
Тому ті інші потоки/потік, які хотіли виконувати свої операції — вони так їх і не виконають, тому і відбуваються “прослизання“ в інкрементації лічильника.

*1 — кожен монітор володіє зовнішньою чергою, зовнішня вона тому, що за нею слідкує сама ОС.
Це waiting-list потоків, які хочуть зайняти монітор і виконати відповідні операції.

*2 — Числові врапери є імутабельними. Вони всередині реалізовані за патерном "Одинак" і будь-яка спроба підкрутити йому значення/змінити стан об’єкта, призводить до того, що цей об’єкт зникне.


https://puredanger.github.io/tech.puredanger.com/2009/01/28/java-concurrency-bugs-synchronize-object/

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

  • Чохли для iPhone 15: повний гід по кольорах, матеріалах і виробниках

    Перед тим як вибрати чохли для iPhone 15, варто визначитися, що саме ви хочете отримати від аксесуара. Комусь потрібен тонкий прозорий корпус, інший покупець шукає посилений захист, а для когось вирішальним стане колір або підтримка MagSafe

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

    Чохли Для Iphone
  • Як побудована програма Meest China Academy

    Курс про товарний бізнес охоплює різні етапи роботи: від пошуку ідеї до перевірки товару, логістики та масштабування. Програма Meest China Academy містить 17 модулів, які послідовно розкривають ці теми без зведення всього навчання до однієї універсальної поради.

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

    Meest
  • Які технології використані в Айфон 17

    Айфон 17 поєднує OLED-дисплей із частотою до 120 Гц, чип A19, дві камери Fusion 48 Мп і швидке заряджання через USB-C. У COMFY можна купити Айфон 17 з накопичувачем на 256 або 512 ГБ, вибравши конфігурацію відповідно до обсягу фото, відео та застосунків

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

    Iphone 17
  • Як вибрати вживаний iPhone: коротке керівництво для розумної покупки

    Вторинний ринок смартфонів Apple активно зростає, і питання, як вибрати вживаний iPhone, стає актуальним для дедалі більшої кількості користувачів. Правильний підхід дозволяє отримати бу iPhone з актуальною iOS і доброю камерою за помітно нижчу ціну, ніж у нових пристроїв.

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

    Iphone
  • Як подолати жіночу безплідність за допомогою донорських яйцеклітин

    Діагноз "безпліддя" рідко звучить як вирок одразу. Для багатьох жінок саме в цей момент вперше звучить словосполучення "донорські яйцеклітини" — і це часто не кінець шляху до материнства, а якраз новий, реальний шанс.

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

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

Java Software Engineer

40Довгочити
9.4KПерегляди
104Підписники
На Друкарні з 19 квітня 2023

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

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

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

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

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

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

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

    Computer Science

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

  • Прискорення компіляції Rust коду

    Мова програмування Rust має дві сторони: блискавично швидкий код, але й неймовірно повільну компіляцію. Цей недолік дратує розробників і стає постійним предметом жартів.

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

    Rust

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

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

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

  • Прискорення компіляції Rust коду

    Мова програмування Rust має дві сторони: блискавично швидкий код, але й неймовірно повільну компіляцію. Цей недолік дратує розробників і стає постійним предметом жартів.

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

    Rust