Представьте себе что-то вроде этого:
function A():
lock (X)
B()
unlock (X)
function B():
A()
Теперь мы вызываем A. Происходит следующее:
. Поскольку мы никогда не выходили из первого вызова A, X все еще заблокирован. Это называется повторным входом - пока функция A еще не вернулась, функция A вызывается снова. Если A полагается на какое-то глобальное статическое состояние, это может привести к ошибке «повторного входа», где до того, как статическое состояние будет очищено от выхода функции, функция будет запущена снова, а половина вычисленных значений столкнется с началом второй вызов.
В этом случае мы сталкиваемся с блокировкой, которую мы уже удерживаем. Если замок заново узнает, он поймет, что мы являемся тем же самым потоком, который удерживает блокировку уже и пропустим. В противном случае он будет тупик навсегда - он будет ждать блокировки, которую он уже удерживает.
В java, lock
и synchronized
являются повторными входами - если блокировка удерживается нитью, и нить пытается переустановить один и тот же замок, это разрешено. Поэтому, если бы мы написали вышеописанный псевдокод в Java, он бы не зашел в тупик.