2010-10-03 2 views
1

Я читал, что следующий класс не является потокобезопасным, так как потоки могут читать несогласованные данные, так как есть вероятность, что поток прочитает масштабированную версию real и немасштабированную версию imaginary. Но я не понимал, как это сделать.Java: безопасность потоков в классе с синхронизированными методами

Я был под впечатлением, что если поток получает блокировку и в scale() метод, никакой другой поток не может быть в getReal() или getImaginary() методов в то же время, так что другие потоки не могут читать «половину масштабируется» комплексных чисел. Это не правильно?

class Complex 
    { 
     double real; 
     double imaginary; 

     synchronized void scale(double scaleFactor) 
     { 
      real = real * scaleFactor; 
      imaginary = imaginary * scaleFactor; 
     } 

     synchronized double getReal() 
     { 
       return real; 
     } 

     synchronized double getImaginary() 
     { 
       return imaginary; 
     } 
    } 

ответ

5

Рассмотрим следующий сценарий:

  1. Thread А вызывает getReal()
  2. Thread B вызывает scale()
  3. Поток А вызывает getImaginary()

Таким образом Thread А может действительно получить непоследовательным реальной и мнимой значения.

Решение будет либо

  • создать единый синхронизированный метод получения для возврата оба значения сразу, или
  • сделать класс неизменны, как это было предложено Вивьен.
2

никакой другой поток не может быть в GetReal() или getImaginary() методов, в то же время, так что другие потоки не могут читать «» половину масштабированные комплексные числа. Это не правильно?

Да, это верно, однако ...

Как Дуглас указывает, любой клиент, который необходим доступ к реальной и мнимой части должен выполнить два отдельных вызова: один real() и один в imaginary() (в котором другой поток мог бы звонить между scale). У вас нет расчётов данных, но поведение может по-прежнему зависеть от планирования.

Кроме того, вам необходимо указать , чтобы поля были закрытыми, otherwie подкласс или классы в одном пакете могли видеть комплексное число «обновленный».

4

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

В этом случае ваш метод масштабирования создает и возвращает новый объект Complex с новыми значениями.

Обратите внимание, что все модели JVM Number работают.

+1

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

2

Любой клиент вашего класса должен позвонить getReal(), затем getImaginary(), если они хотят выполнять вычисления с обеих сторон.

Эти вызовы могут окружать звонок scale() из другого потока.

Возможно, лучшим решением является сделать класс Complex неизменным, поскольку в противном случае вам придется сделать много других бит сложным для блокировки & разблокировать объекты.

Смежные вопросы