2016-12-27 9 views
4

Я читал source code of PriorityBlockingQueue в Java, и мне было интересно:Что может быть причиной блокировки/разблокировки в PriorityBlockingQueue?

  1. почему это tryGrow() метода рилизинга замка приобрел во время предложений() метода, просто делать свое дело не- блокировка, а затем снова заблокировать, когда готовы заменить содержимое очереди? я имею в виду, он мог бы просто сохранить замок, который у него был ...
  2. Как это работает? растущая очередь, которая включает в себя копию массива, не вызывает неправильного поведения при одновременных добавлениях, где дополнительные добавления могут полностью возникать, когда текущее добавление увеличивает размер очереди?

ответ

3

Поскольку распределение памяти может быть сравнительно медленным и может быть выполнено, когда массив разблокирован.

Отпустив замок, он позволяет другим потокам продолжать работу, когда он выделяет (потенциально большой) новый массив.

Как этот процесс можно сделать без замков, это хорошая практика. Вы должны удерживать блокировку только на минимальный период времени.

Достаточные проверки сделаны, чтобы гарантировать, что ни одна другая нить не делает это одновременно.

UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset, 0, 1) 

разрешает только один поток в этот раздел кода за раз.

Обратите внимание на

lock.lock(); 
if (newArray != null && queue == array) { 

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

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

Как Kamil красиво объясняет.

Назначение этой разблокировки - это только убедиться, что более быстрый поток будет увеличивать очередь, поэтому мы не будем тратить время на блокировку «лучших».

+1

Я хотел бы добавить, что, на мой взгляд, после прочтения кода это позволит разрешить другим потокам расы растущего массива. Они в основном не могут ничего сделать. Если кто-то идет к tryGrow, мы можем быть уверены, что другой, который пытается поместить элемент, после того, как блокировка будет выпущена, может пойти только на tryGrow. Цель этой разблокировки - только убедиться, что более быстрый поток будет увеличивать очередь, поэтому мы не будем тратить время на блокировку «лучших». Надеюсь, это имеет смысл для вас :) –

+0

@ Kamil, действительно, это имеет большой смысл. Тем не менее, я беспокоюсь, когда один поток выпущен и находится в процессе роста, в то время как следующий пытался расти, пропускает (потому что начальный уже растет), и идет и заменяет очередь – Belun

+1

Видите ли, он не делает что благодаря if (newArray! = null && queue == array), newArray будет null, потому что другой выделяет. Он будет в мертвой петле блокировки и разблокировки блокировки, пока другой не попытается ее вырастить.И после этого они поместят свои значения, и поток, который стал массивом, будет первым благодаря блокировке перед заменой очереди. В основном, быстрее будет идти сначала, если в tryGrow, а остальное придется ждать –