Должен ли я синхронизироваться в ReferenceQueue?

Я смотрел исходный код WeakHashMap и наткнулся на это:

private final ReferenceQueue<Object> queue = new ReferenceQueue<>();

private void expungeStaleEntries() {
    for (Object x; (x = queue.poll()) != null; ) {
        synchronized (queue) {
           /* snip */
        }
    }
}

Почему этот метод синхронизируется с ReferenceQueue? WeakHashMap сам не претендует на то, чтобы быть потокобезопасным:

Как и большинство классов коллекций, этот класс не синхронизирован. синхронизированный WeakHashMap может быть построен с использованием Метод Collections.synchronizedMap.

Это заставило меня поверить, что эта деталь реализации должна каким-то образом обеспечить безопасность потока самого ReferenceQueue (так как GC будет модифицировать его из собственного Thread). Однако документация для ReferenceQueue ничего не упоминает о каких-либо проблемах concurrency и взгляните на исходный код для ReferenceQueue показывает, что он даже не синхронизируется сам по себе (он использует внутренний замок).

Почему WeakHashMap синхронизируется на ReferenceQueue? Должен ли я синхронизироваться на ReferenceQueue каждый раз, когда я его использую?

Ответ 1

Если вы посмотрите ReferenceQueue, вы увидите, что он явно поддерживает потоки внутри платформы, поскольку он утверждает, что метод remove() будет блокироваться до тех пор, пока не будет доступна новая запись.

synchronized, который вы видите в WeakHashMap, заключается в обеспечении правильной синхронизации нескольких потоков, обращающихся к ReferenceQueue.

Вы можете найти этот связанный bug at bugs.sun.com интересный.

Чтобы ответить на ваш вопрос, я думаю, что внешняя синхронизация ReferenceQueue не требуется, если вы обеспечиваете доступ только к одному потоку. Я бы не использовал (и не могу придумать вескую причину) использовать один ReferenceQueue как потребитель из нескольких потоков.