Как правильно бороться с ложным пробуждением?
Я читаю 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
должен быть потокобезопасным (например, переменные).