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

0
Yogesh Katkar 18 Ноя 2019 в 09:45
4
Да, они могут..
 – 
Andy Turner
18 Ноя 2019 в 09:52
Если бы мне задали этот вопрос в интервью, я бы попросил показать пример кода на доске. Вопрос, как написано выше, можно интерпретировать по-разному.
 – 
Solomon Slow
18 Ноя 2019 в 18:10
P.S. Я бы начал с указания, что «синхронизированный метод» на самом деле просто синтаксический сахар для метода, тело которого является синхронизированным блоком block . Тогда я бы говорил только о поведении синхронизированных блоков, которое легче объяснить.
 – 
Solomon Slow
18 Ноя 2019 в 18:13

2 ответа

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

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

Замок не принадлежит потоку. Блокировка фактически принадлежит объекту (или классу в случае блокировки уровня класса), а поток получает блокировку объекта (или класса в случае блокировки уровня класса) в синхронизированном контексте.

2
Shankar Saran Singh 18 Ноя 2019 в 09:50

Этот:

class SomeType {
    synchronized SomeOtherType Foobar() {...}
}

Это просто краткий способ написания этого:

class SomeType {
    SomeOtherType Foobar() {
        synchronized(this) {
            ...
        }
    }
}

И это:

class SomeType {
    static synchronized SomeOtherType Foobar() {...}
}

Это просто краткий способ написания этого:

class SomeType {
    static SomeOtherType Foobar() {
        synchronized(SomeType.class) {
            ...
        }
    }
}

Поэтому каждый вопрос о «синхронизированных методах» может быть сведен к вопросу о синхронизированных блоках.

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

  1. JVM никогда не позволит двум потокам одновременно выполняться в блоках, которые synchronized (o) находятся в одном экземпляре o, * и
  2. Независимо от того, что один поток делает для изменения общих объектов до его выхода из блока synchronized (o), он гарантированно станет видимым для другого потока к тому времени, когда другой поток войдет в любой блок, синхронизированный в том же экземпляре o.

* Это немного усложняется вызовом o.wait() внутри блока synchronized (o). Вызов wait () снимает блокировку до того, как начинает ждать, а затем повторно получает блокировку до ее возврата.

Говоря технически, любые числовые потоки могут быть «в» synchronized (o) блоках для одного и того же экземпляра o, если все, кроме одного из этих потоков, ожидают вызова o.wait(), но я предпочитаю скажем, что только один поток может выполнить в синхронизированном блоке и что "ожидание" не считается "выполнением".

1
Solomon Slow 18 Ноя 2019 в 20:34