Gary Tully, I don't think we need to do anything here other than to grab the sendLock to prevent new messages from coming in while the purge is running and works its way through all the pending messages in the queue including already dispatched messages (we can also remove the line of code that sets the count to 0 which isn't necessary)
For messages that are already dispatched we don't seem to need to worry about the ack doing a double decrement. If the Queue has been purged and the already dispatched messages are acked later the metrics don't double decrement because in dropMessage() there is a dropIfLive() check that will fail. This scenario is already shown if you look at QueuePurgeTest and run testPurgeLargeQueueWithConsumer. This test shows that after a purge if the consumer acks the messages already in prefetch the messages count doesn't go negative.
I suppose an argument could be made that we should clear out the dispatch list in each subscription to save memory but then if messages are acked we'd get a bunch of unmatched acknowledge warnings in the log because assertAckMatchesDispatched() in PrefetchSubscription would throw a bunch of exceptions when the acks came in.