Синхронизаниция по Integer в Java

146
21 декабря 2019, 05:20

Есть следующая учебная программка.

В программе есть синхронизированный блок. Синхронизация работает если использовать в качестве объекта синхронизации что угодно и даже массив values, но не работает при использовании Integer count.

synchronized (count) {
    incrementCount();
    values[getCount()]++;
}

В тоже время если объявить другой объект Integer, то синхронизация по нему будет работать.

synchronized (other) {
    incrementCount();
    values[getCount()]++;
}

Почему нельзя использовать синхронизацию по count?

public class Solution {
    public static void main(String[] args) throws InterruptedException {
        Counter counter1 = new Counter();
        Counter counter2 = new Counter();
        Counter counter3 = new Counter();
        Counter counter4 = new Counter();
        counter1.start();
        counter2.start();
        counter3.start();
        counter4.start();
        counter1.join();
        counter2.join();
        counter3.join();
        counter4.join();
        for (int i = 1; i <= 100; i++) {
            if (values[i] != 1) {
                System.out.println("Массив values содержит элементы неравные 1");
                break;
            }
        }
    }
    public static Integer count = 0;
    public static int[] values = new int[105];
    static {
        for (int i = 0; i < 105; i++) {
            values[i] = 0;
        }
    }
    public static void incrementCount() {
        count++;
    }
    public static int getCount() {
        return count;
    }
    public static class Counter extends Thread {
        @Override
        public void run() {
            do {
                synchronized (count) {
                    incrementCount();
                    values[getCount()]++;
                }
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                }
            } while (getCount() < 100);
        }
    }
}
Answer 1

Объекты типа Integer иммутабельны, операция инкремента count++ не меняет состояние объекта по ссылке, после инкремента переменная count будет ссылаться на другой объект в куче.

Integer count = 0; 
...
synchronized (count) {
     incrementCount(); // тут происходит count++;
     ...
}

Что тут происходит:

  1. Вы захватываете монитор (MonitorEnter) на объекте, доступном по ссылке count.

  2. Вы инкрементируете значение count, теперь count ссылается на новый Integer.

  3. В секцию synchronized может зайти другой поток, т.к. по ссылке count объект, на котором еще не произошел MonitorEnter.

Как-то так.

READ ALSO
Из активити не обновляется RecyclerView во фрагменте

Из активити не обновляется RecyclerView во фрагменте

При нажатии кнопки меню в MainActivity обновляются данные, изпользуемые в RecyclerViewСам рецайклер сидит во фрагменте, пытаюсь сообщить ему, что данные...

141
Вопрос по строковому методу length в java

Вопрос по строковому методу length в java

В примерах кода в своей книге ("Структуры данных и алгоритмы") Лафоре не пользуется методом lengthА отдельно объявляет дину массива, например...

149
Почему android studio подчёркивает переменную?

Почему android studio подчёркивает переменную?

myRad имеет тип floatКто-нибудь знает, что нужно исправить? У меня есть другие переменные float, но они не подчёркнуты

163