Как правильно бороться с ложным пробуждением?

Я читаю Curatorисходный код, и нашел код ниже:

            while ( (client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock )
        {
            List<String>        children = getSortedChildren();
            String              sequenceNodeName = ourPath.substring(basePath.length() + 1); // +1 to include the slash

            PredicateResults    predicateResults = driver.getsTheLock(client, children, sequenceNodeName, maxLeases);
            if ( predicateResults.getsTheLock() )
            {
                haveTheLock = true;
            }
            else
            {
                String  previousSequencePath = basePath + "/" + predicateResults.getPathToWatch();

                synchronized(this)
                {
                    try 
                    {
                        // use getData() instead of exists() to avoid leaving unneeded watchers which is a type of resource leak
                        client.getData().usingWatcher(watcher).forPath(previousSequencePath);
                        if ( millisToWait != null )
                        {
                            millisToWait -= (System.currentTimeMillis() - startMillis);
                            startMillis = System.currentTimeMillis();
                            if ( millisToWait <= 0 )
                            {
                                doDelete = true;    // timed out - delete our node
                                break;
                            }

                            wait(millisToWait);
                        }
                        else
                        {
                            wait();
                        }
                    }
                    catch ( KeeperException.NoNodeException e ) 
                    {
                        // it has been deleted (i.e. lock released). Try to acquire again
                    }
                }
            }
        }

Я читаю Javadoc от Object и всегда должен проверять состояние в циклах, например так:

 synchronized (obj) {
     while (condition does not hold&)
        obj.wait(timeout);
         ... // Perform action appropriate to condition
 }

какой код правильный?

Обновить

Вот исходный код Curator,

Так как haveTheLock является локальной переменной, никакой другой поток не изменит ее, поэтому код работает нормально.

1 ответ

Синхронизированный блок находится в цикле while.

И у него есть две ветви:

  • бесконечный wait(): нет условий для проверки
  • время wait(millisToWait) и количество миллисекунд ожидания пересчитывается в каждом цикле

Так что ложные пробуждения не будут иметь никакого эффекта. Основная причина наличия цикла while внутри синхронизированного блока, как в javadoc, заключается в том, что очень часто вам нужна синхронизация, чтобы убедиться, что результат условия виден.

В коде, который вы показываете, я имею в виду, что оба client.getState() а также haveTheLock должен быть потокобезопасным (например, переменные).

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