Можете ли вы безопасно синхронизировать параметр Java?

Возьмите этот код:

public class MyClass {
    private final Object _lock = new Object();
    private final MyMutableClass _mutableObject = new MyMutableClass()

    public void myMethod() {
        synchronized(_lock) { // we are synchronizing on instance variable _lock
            // do something with mutableVar 
            //(i.e. call a "set" method on _mutableObject)
        }
    }
}

Теперь представьте себе делегирование кода внутри myMethod() в некоторый вспомогательный класс, где вы передаете блокировку

public class HelperClass {
    public helperMethod(Object lockVar, MyMutableClass mutableVar) {
        synchronized(lockVar) { // we are now synchronizing on a method param, 
                                // each thread has own copy
            // do something with mutableVar 
            // (i.e. call a "set" method on mutableVar)
        }
    }
}

может ли "myMethod" быть переписано, чтобы использовать HelperClass, передав его lock var, чтобы все по-прежнему было потокобезопасным? т.е.

public void myMethod() {
    _helperObject.helperMethod(_lock, _mutableObject);
}

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

Ответ 1

Синхронизация выполняется с помощью объектов, а не переменных.

Переменные/члены [иногда] содержат объекты, и это результирующий объект, содержащийся в [variable] x, который фактически синхронизируется в synchronized(x).

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

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

Счастливое кодирование.