Несогласованное нарушение синхронизации

Я получил это нарушение при возврате в следующем методе:

protected Token getAccessToken() {  
    synchronized (this) {
        if (token == null || isExpired(token))
            token = createToken();
    }

    return token; // <-- Inconsistent synchronization of blablabla.token; locked 75% of time
}

Есть ли проблемы с видимостью, связанные с token поле? Как я понимаю после synchronized блочный токен должен иметь свое последнее значение.

Я что-то упустил или это ложный положительный результат?

2 ответа

Решение

Учтите следующее:

  • Thread1: вводит метод
  • Thread2: вводит метод
  • Thread1: вводит блок синхронизации, токен не равен NULL и не имеет срока действия
  • Thread1: выход из блока синхронизации
  • Поток 2: вводит блок синхронизации, токен не нулевой, но истек
  • Thread2: назначает новый токен
  • Thread1: возвращает токен (может быть новым значением, назначенным потоком 2, может быть старым значением)
  • Thread2: выход из блока синхронизации
  • Thread2: возвращает (новый) токен

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

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

Поток A может вернуть токен, который был только что воссоздан потоком B, потому что токен истек.

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

Другие вопросы по тегам