Я попытаюсь добавить пример, чтобы прояснить ситуацию.
Как уже упоминалось, синхронизация в Java является реализацией концепции Monitor . Когда вы помечаете блок кода как синхронизированный, вы используете объект в качестве параметра. Когда исполняющий поток приходит к такому блоку кода, он должен сначала подождать, пока не будет другого исполняющего потока в синхронизированном блоке с тем же объектом.
Object a = new Object();
Object b = new Object();
...
synchronized(a){
doStuff();
}
...
synchronized(b){
doSomeStuff();
}
...
synchronized(a){
doOtherStuff();
}
В приведенном выше примере поток, выполняющий doOtherStuff()
, заблокирует другой поток от входа в блок кода, защищающий doStuff()
. Однако поток может без проблем войти в блок около doSomeStuff()
, поскольку он синхронизируется на Object b
, а не Object a
.
Когда вы используете синхронизированный модификатор в методе экземпляра (нестатический метод), это очень похоже на наличие синхронизированного блока с «this» в качестве аргумента. Таким образом, в следующем примере methodA()
и methodB()
будут действовать одинаково:
public synchronized void methodA() {
doStuff();
}
...
public void methodB() {
synchronized(this) {
doStuff();
}
}
Обратите внимание, что если у вас есть methodC()
в этом классе, который не синхронизирован и не имеет синхронизированного блока, ничто не помешает потоку войти в этот метод, и неосторожное программирование может позволить этому потоку получить доступ к небезопасному коду в объект. * * тысяча двадцать-один
Если у вас есть статический метод с модификатором synchronized, это практически то же самое, что иметь синхронизированный блок с ClassName.class
в качестве аргумента (если у вас есть объект этого класса, ClassName cn = new ClassName();
, вы можете получить к нему доступ объект с Class c = cn.getClass();
)
class ClassName {
public void static synchronized staticMethodA() {
doStaticStuff();
}
public static void staticMethodB() {
synchronized(ClassName.class) {
doStaticStuff();
}
}
public void nonStaticMethodC() {
synchronized(this.getClass()) {
doStuff();
}
}
public static void unSafeStaticMethodD() {
doStaticStuff();
}
}
Итак, в приведенном выше примере staticMethodA()
и staticMethodB()
действуют одинаково. Выполняющему потоку также будет заблокирован доступ к блоку кода в nonStaticMethodC()
, поскольку он синхронизируется с тем же объектом.
Однако важно знать, что ничто не помешает исполняющему потоку получить доступ к unSafeStaticMethodD()
. Даже если мы говорим, что статический метод «синхронизируется с объектом Class», это не означает, что он синхронизирует все обращения к методам в этом классе. Это просто означает, что он использует объект Class для синхронизации. Небезопасный доступ все еще возможен.