Разумно ли синхронизировать по локальной переменной?

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

и другое потоки не могут получить доступ к этим локальным переменным.

Итак, в каком случае мы должны синхронизироваться по локальным переменным?

4 ответов


есть две ситуации:

  1. локальная переменная имеет примитивный тип, например int или double.
  2. локальная переменная имеет ссылочный тип, например ArrayList

В первой ситуации, вы не могу synchronize, так как вы можете синхронизировать только объекты (на которые указывают переменные ссылочного типа)

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

примеры: вы назначили локальную переменную из static или поля экземпляра, или вы получили объект из общей коллекции.

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


вы говорите о приведенном ниже случае:

public class MyClass {
    public void myMethod() {
        //Assume Customer is a Class
        Customer customer = getMyCustomer();
        synchronized(customer) {
            //only one therad at a time can access customer object
              which ever holds the lock
        }
    }
}

В приведенном выше коде customer является локальной ссылочной переменной, но вы все еще используете synchronized block ограничить доступ к объекту customer указывает на (по одной нити за раз).

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

короче, когда вы говорите локальную переменную (не примитивную), только ссылка локальна, но не сам фактический объект, т. е. он фактически ссылается на объект в куче который может быть доступен многими другими потоками. Из-за этого вам нужна синхронизация на объекте, чтобы один therad мог получить доступ только к этому объекту одновременно.


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

таким образом: если вам нужна синхронизация, это всегда больше чем одним потоком. И конечно же, тогда вам нужно зафиксироваться на чем-то, что все эти потоки имеют доступ.

или другими словами: нет смысла вы замок двери чтобы предотвратить сами от входа в здание.

но, как указывает другой ответ: это на самом деле зависит от определения "локальной" переменной. Допустим, у вас есть:

void foo() {
  final Object lock = new Object();
  Thread a = new Thread() { uses lock
  Thread b = new Thread() { uses lock

затем убедитесь, что" локальная " переменная может использоваться в качестве блокировки для этих двух потоков. И помимо этого: этот пример работает, потому что синхронизация происходит на монитор конкретного объекта. И объекты находятся в куче. Все они.


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