Ответ 1
Я попытаюсь добавить пример, чтобы сделать это более ясным.
Как уже упоминалось, синхронизация в 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" в качестве аргумента. Итак, в следующем примере методыA() и methodB() будут действовать одинаково:
public synchronized void methodA() {
doStuff();
}
...
public void methodB() {
synchronized(this) {
doStuff();
}
}
Обратите внимание, что если у вас есть методC() в этом классе, который не синхронизирован и не имеет синхронизированного блока, ничто не остановит поток от ввода этого метода, и небрежное программирование может позволить этому потоку получить доступный небезопасный код в объект.
Если у вас есть статический метод с синхронизированным модификатором, это практически то же самое, что синхронизировать блок с 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 для синхронизации. Небезопасный доступ по-прежнему возможен.