Какой способ выбрать, чтобы сделать поток класса безопасным? - PullRequest
0 голосов
/ 18 декабря 2018

У меня есть код, как показано ниже

class classA {

   int sum = 0;
   void recursiveMethodA {
       sum = sum +1; // For simplicity
   }
}

В основном я делаю некоторые операции в рекурсивном методе, который работает, скажем, 10 раз, и меняю состояние на уровне класса.Но этот класс не является потокобезопасным.

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

class class B {
    // Public exposed method
    public void methodB {
        ClassA classA = new ClassA();
        classA.recursiveMethodA();
    }
}

Моя логика заключается в том, что, поскольку я создаю объект классаВнутри метода класса B он создается в стеке, а не в куче, и, следовательно, он безопасен для потоков.

Правильна ли эта логика?Пожалуйста, предложите альтернативные варианты.

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Моя логика заключается в том, что, поскольку я создаю объект класса A внутри метода класса B, он создается в стеке, а не в куче, и, следовательно, он безопасен для потоков.

Вашлогика и / или терминология не верны.На самом деле, экземпляр ClassA находится в куче.Все обычные объекты Java создаются в куче!

Ваш код на самом деле поточно-ориентирован , но правильное объяснение выглядит следующим образом:

  1. Объектсоздан, и единственная ссылка на него назначена локальной переменной.
  2. При проверке ни один другой поток не может увидеть эту переменную.
  3. При проверке ссылка на объект никогда не передается другойнить;то есть это не опубликовано .
  4. Точки 1., 2. и 3. означают, что объект ограничен потоком 1 дляего полное время жизни.
  5. Поскольку объект ограничен потоком, нет необходимости учитывать безопасность потоков.

Недостаточно сказать (просто), чтоиспользуется локальная переменная:

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

  • Также необходимо учитывать, что значение в переменной может быть передано другому потоку.

Финализация и обработка ссылок будут выполняться в другом потоке.Однако это НЕ должно представлять проблему безопасности потока.(Спецификация JLS заботится о финализации, а javadoc для Reference заботится о ссылках. В обоих случаях происходит до в соответствующих точках.)


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


Вы имеете в виду, что classA является потокобезопаснымсам?

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

Разве я не должен определять класс как потокобезопасный во всех контекстах?Я не знаю, как завтра это может быть использовано?

Это зависит от вас!

Но учтите следующее: большое количество стандартных классов Java НЕ ориентировано на многопотоковое исполнение.Действительно, классический случай - StringBuilder, который является не-ориентированным на многопоточность повторным реализацией StringBuffer.Другие являются большинством типов коллекций в java.util!

По сути, у вас есть два варианта:

  • Сделать класс по своей сути поточно-ориентированным и принять, что это происходитс накладными расходами во время выполнения.

  • Сделайте класс по своей природе не поточно-ориентированным и убедитесь, что вы используете его только теми способами, которые решают эту проблему соответствующим образом.(Один из способов - ограничить экземпляры потоками. Другой - использовать некоторую форму внешней синхронизации.)

0 голосов
/ 18 декабря 2018

Самый простой способ иметь поточно-ориентированную функцию - поставить ключевое слово "synchronized"

synchronized public void method() {
  //do something
}
...