В Java нужно ли синхронизировать методы, которые не используют статические переменные или переменные класса? - PullRequest
7 голосов
/ 22 января 2011

Методы, которые используют только локальные переменные внутри, страдают от каких-либо проблем с потоками?Где-то было упомянуто, что метод с локальными переменными копируется в каждый фрейм стека потоков для работы и не требует синхронизации для многопоточной реализации, если он не использует уровень класса или статические ссылки / переменные?

Ответы [ 4 ]

8 голосов
/ 22 января 2011

Если ваш метод работает только с параметрами и локально определенными (в отличие от членов класса) переменными, то проблем с синхронизацией не возникает.

Но ...

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

int doSomething(int myParameter)
{
  MyObject working_set = new MyObject();
  interim = working_set.doSomethingElse(myParameter);
  return working_set.doSomethingElseAgain(interim);
}

Экземпляр MyObject создается в вашем методе, выполняет всю свою работу в вашем методе и кашляет.до крови, ожидая, когда GC будет отбракована при выходе из вашего метода.

С другой стороны, это может быть проблемой:

int doSomething(int myParameter)
{
  MyObject working_set = new MyObject();
  interim = working_set.doSomethingElse(myParameter);
  another_interim = doSomethingSneaky(working_set);
  return working_set.doSomethingElseAgain(another_interim);
}

Если вы точно не знаете, что происходитв doSomethingSneaky() может потребоваться синхронизация где-либо.В частности, вам может потребоваться выполнить синхронизацию с операциями на working_set, потому что doSomethingSneaky() может сохранить ссылку на ваш локальный объект working_set и передать ее другому потоку, пока вы все еще делаете что-то в своем методе или вworking_set методы.Здесь вам нужно быть более оборонительным.

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

4 голосов
/ 22 января 2011

Разве методы, которые используют только локальные переменные внутри, не страдают от каких-либо проблем с потоками?

Верно в очень упрощенном смысле, но давайте проясним - я думаю, что это верно, только если:

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

  • такой метод вызывает только методы, которые являются потокобезопасными.

В некоторых случаях эти правила могут быть нарушены:

  • Локальная переменнаяможет быть инициализирован, чтобы указывать на объект, который также доступен вне метода.Например, локальная переменная может указывать на синглтон (Foo bar = Foo.getSingleton()).

  • Локальный экземпляр, содержащийся в локальной переменной, может «просочиться», если экземпляр передается в качестве аргументавнешний метод, который хранит ссылку на экземпляр.

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

1 голос
/ 22 января 2011

Вопрос очень общий, поэтому, пожалуйста, не ожидайте никакой конкретики от моего ответа.

1_ Нам нужно быть более осторожными со статическими методами, чем, скажем, с методами экземпляра.

2_ @Justmycorrectopinion - это правильно, но некоторые из описанных им терминов должны быть более тщательно проработаны, чтобы быть совершенными.(Даже если статический метод работает только с локальной переменной, все еще существует возможность состояния гонки.)

3_ Для меня есть простые правила, которые помогли мне проанализировать безопасность потоков.

Понять, является ли каждый компонент, инкапсулированный в нем, совместным или нет.Таким образом, самое простое решение состоит в том, чтобы уменьшить область видимости всех переменных и увеличить область видимости только в случае крайней необходимости, и если компонент выполняет мутацию объекта, это обычно не безопасно для потоков.

4_ Используйте поддержку инструментов для выполнения статического анализа кода на предмет безопасности потоков.(Идея имеет плагин checkthread).

5_ Никогда не используйте статический метод для выполнения мутации объекта.Если вызов статической переменной вызывает мутацию объекта, то разработчик просто обходит OOPS.

6_ Всегда документируйте безопасность потоков.Помните, что при разработке не обязательно синхронизировать какой-либо метод, но его можно сделать не очень безопасным для потоков.

7_ И последнее, но, пожалуй, самое важное, убедитесь, что большинство ваших объектов неизменны.По моему опыту, большую часть времени мне никогда не приходилось делать многие мои объекты изменяемыми.(В редких случаях, когда необходимо изменить состояние объекта, защитное копирование / создание нового объекта почти всегда лучше.)

0 голосов
/ 22 января 2011

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

...