public void endGiiQueueing() {
    giiLock.writeLock().lock();
    final boolean isDebugEnabled = logger.isDebugEnabled();
    try {
      giiCount.decrementAndGet();
      if (isDebugEnabled) {
        logger.debug("{}: endGiiQueueing count is now {}", regionName, giiCount);
      }
      if (giiCount.get() < 0) {
        if (isDebugEnabled) {
          logger.debug("{} found giiCount to be {}", regionName, giiCount);
        }
        giiCount.set(0);
      }
      if (giiCount.get() == 0) {
        if (isDebugEnabled) {
          logger.debug("{} all GII requests completed - draining {} messages", regionName,
              giiQueue.size());
        }
        boolean interrupted = false;
        int actualCount = 0;
        while (true) {
          Object value;
          try {
            value = giiQueue.remove();
          } catch (NoSuchElementException ignore) {
            break;
          }
          actualCount++;
          try {
            if (isDebugEnabled) {
              logger.debug("{} draining #{}: {}", regionName, (actualCount + 1), value);
            }
            if (value instanceof HAEventWrapper) {
              if (((HAEventWrapper) value).getClientUpdateMessage() == null) {
                if (isDebugEnabled) {
                  logger.debug(
                      "{} ATTENTION: found gii queued event with null event message.  Please see bug #44852: {}",
                      regionName, value);
                }
                continue;
              }
            }

            basicPut(value);

            // The HAEventWrapper putInProgressCounter must be decremented because it was
            // incremented when it was queued in giiQueue.
            if (value instanceof HAEventWrapper) {
              ((HAEventWrapper) value).decrementPutInProgressCounter();
            }
          } catch (NoSuchElementException ignore) {
            break;
          } catch (InterruptedException ignore) {
            // complete draining while holding the write-lock so nothing else
            // can get into the queue
            interrupted = true;
          }
        }
        if (interrupted) {
          region.getCache().getCancelCriterion()
              .checkCancelInProgress(new InterruptedException());
          Thread.currentThread().interrupt();
        }
      }
    } catch (RuntimeException t) {
      logger.fatal("endGiiQueueing terminating due to uncaught runtime exception", t);
      throw t;
    } catch (Error t) {
      logger.fatal("endGiiQueueing terminating due to uncaught error", t);
      throw t;
    } finally {
      if (logger.isTraceEnabled()) {
        logger.trace("{} endGiiQueueing completed", regionName);
      }
      giiLock.writeLock().unlock();
    }
  }
at the end of a GII image request we decrement the in-process count and, if it falls to zero we
empty the list of messages that put() has been building. This is done with the lock held to
prevent newer events from being queued before the list is drained.
geode-core/src/main/java/org/apache/geode/internal/cache/ha/HARegionQueue.java