в Java мне нужно отметить поле int как изменчивое, если потоки увеличивают его только в синхронном методе? [Дубликат]

Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.

Например, ниже - класс ученика, который будет использовать его в нашем коде.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Приведенный ниже код дает вам исключение с нулевым указателем.

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}

Поскольку вы используете Obj_Student, но вы забыли инициализировать его, как в правильном коде, показанном ниже:

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student = new Student();
            obj_Student.setId(12);
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}
3
задан Rafael Winterhalter 12 December 2014 в 12:11
поделиться

2 ответа

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

Летучие, как и синхронизированные, имеют привязки к памяти, которые связаны с ним - в зависимости от процессора он является хранилищем / нагрузкой / полным барьером, который гарантирует, что обновление из одного потока будет видимым для других (-ов). Я предполагаю, что это выполняется с использованием недействительности кэша cpu .

ИЗМЕНИТЬ Из того, что я только что прочитал, буферы хранилища сброшены в кэш CPU, и это то, как видимость достигнуты.

7
ответ дан Eugene 17 August 2018 в 14:26
поделиться
  • 1
    Где в JLS это поведение описано? – jarnbjo 4 April 2014 в 13:05
  • 2
    @jarnbjo Раздел модели памяти Java. – Marko Topolnik 4 April 2014 в 13:10
  • 3
    @jarnbjo, это связано с моделью памяти Java, видимость достигается с помощью барьеров памяти. – Eugene 4 April 2014 в 13:11
  • 4
    Ах, отлично, спасибо. Раздел модели памяти JLS кажется коротким и кратким, но я никогда не могу найти свободные бит, которые действительно помогают мне в реальных ситуациях. Если это не так много, чтобы спросить, не могли бы вы указать / вставить соответствующий бит, описывающий это поведение? – Bober02 4 April 2014 в 14:12
  • 5
    @ Bober02, если у вас в этой отрасли рано или поздно вы встретитесь & quot; Прекрасный блог Мартина Томпсона, я рад представить вам его. :) mechan-sympathy.blogspot.com/2011/07/… Счастливое чтение! – Eugene 4 April 2014 в 14:15

Упрощенный ответ: если поток A обновляет поле, а затем освобождает блокировку, то поток B будет гарантированно видеть обновление после того, как поток B приобретет ту же блокировку.

Обратите внимание: «отпустите блокировку «означает выход из блока synchronized, а« получение той же блокировки »означает синхронизацию на одном и том же объекте.

1
ответ дан james large 17 August 2018 в 14:26
поделиться
  • 1
    после того, как поток B приобрел тот же самый замок , что не соответствует действительности. Он не должен приобретать блокировку, чтобы увидеть обновление. Простое повторное чтение будет достаточно – Eugene 4 April 2014 в 15:58
  • 2
    @Eugene Прочтите раздел «Модель памяти». в Спецификации языка Java, и обратите внимание на «происходит до», отношения. Если поток A записывает поле и затем разблокирует мьютекс, запись «происходит до», разблокировать. Но если нить B затем читает одно и то же поле без синхронизации на одной и той же блокировке, «& quot; бывает до & quot; отношение: для JVM вполне естественно разрешить потоку B видеть локально кэшированное старое значение поля независимо от того, сколько времени прошло в реальном времени, так как поток A написал его. – james large 4 April 2014 в 17:30
  • 3
    Не путайте разницу между тем, что ваша JVM на самом деле делает в любой конкретный день, с тем, что делает правильно реализованная JVM разрешена . – james large 4 April 2014 в 17:32
  • 4
    Я должен признать, что я всегда думал, что синхронизированный имеет встроенный в него барьер памяти, и эта память будет синхронизирована. Я до сих пор не нашел ссылок на это, но определенно должен синхронизировать одну и ту же блокировку для видимости. Спасибо!! – Eugene 6 April 2014 в 15:02
  • 5
    @Eugene Я, возможно, неправильно понял то, что вы говорили. Я представлял переменную, которая не является изменчивой, поток A записывает переменную внутри синхронизированного блока, но поток B считывает переменную без синхронизации. В этом случае новое значение должно быть сброшено в память, когда поток A покинет синхронизированный блок; но на некоторых архитектурах, если поток B работает на другом ядре, он все еще может видеть старое значение в своем локальном кеше. Я не знаю, случается ли это на практике, но Java Language Spec разрешает его выполнение. – james large 6 April 2014 в 17:07
Другие вопросы по тегам:

Похожие вопросы: