Поточно-безопасный класс в Java с помощью синхронизированных блоков

Допустим, у нас есть очень простой класс Java MyClass.

public class MyClass {
   private int number;

    public MyClass(int number) {
        this.number = number;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }
}

Есть три способа создать потокобезопасный класс Java, который имеет некоторое состояние:

  1. Сделать его действительно неизменяемым

    public class MyClass {
    закрытый конечный номер;
    
    публичный MyClass (целое число) {
    это.число = число;
     }
    
    публичный интервал getNumber () {
    обратный номер;
     }
    
    }
    
  2. Сделать поле числоизменяемым.

    открытый класс MyClass {
    частный изменяемый внутренний номер;
    
    публичный MyClass (целое число) {
    это.число = число;
     }
    
    публичный интервал getNumber () {
    обратный номер;
     }
    
    public void setNumber (целое число) {
    это.число = число;
     }
    }
    
  3. Используйте синхронизированный блок . Классическая версия этого подхода, описанная в главе 4.3.5 Java Concurrency на практике. И самое забавное, что в примере, упомянутом в опечатках к этой книге, есть ошибка.

    открытый класс MyClass {
    частный внутренний номер;
    
    публичный MyClass (целое число) {
    установитьНомер(число);
     }
    
    общедоступный синхронизированный int getNumber () {
    обратный номер;
     }
    
    общедоступный синхронизированный недействительный setNumber (целое число) {
    это.число = число;
     }
    }
    

Есть еще один факт, который следует добавить в контекст обсуждения.В многопоточной среде JVM может свободно переупорядочивать инструкции за пределами синхронизированногоблока, сохраняя логическую последовательность и отношения "происходит до", заданные JVM. Это может привести к публикации объекта, который еще не создан должным образом, в другой поток.

У меня есть пара вопросов по третьему делу.

  1. Будет ли он эквивалентен следующему фрагменту кода:

    public class MyClass {
    частный внутренний номер;
    
    публичный MyClass (целое число) {
    синхронизировано (это) {
    это.число = число;
     }
     }
    
    общедоступный синхронизированный int getNumber () {
    обратный номер;
     }
    
    общедоступный синхронизированный недействительный setNumber (целое число) {
    это.число = число;
     }
    }
    
  2. Будет ли предотвращено изменение порядка в третьем случае или JVM сможет изменить порядок инструкций и, следовательно, опубликовать объект со значением по умолчанию в поле число?

  3. Если ответ на второй вопрос положительный, то у меня есть еще один вопрос.

    открытый класс MyClass {
    частный внутренний номер;
    
    публичный MyClass (целое число) {
    синхронизированный (новый объект ()) {
    это.число = число;
     }
     }
    
    общедоступный синхронизированный int getNumber () {
    обратный номер;
     }
    
    общедоступный синхронизированный недействительный setNumber (целое число) {
    это.число = число;
     }
    }
    

Предполагается, что этот странно выглядящий синхронизированный (новый объект())предотвращает эффект переупорядочения. Это будет работать?

Для ясности: все эти примеры не имеют никакого практического применения. Мне просто любопытны нюансы многопоточности.

19
задан wax 8 March 2012 в 17:30
поделиться