@@ -118,30 +118,25 @@ public void close() {
118118 () -> {
119119 Instant staleBefore = Instant .now ().minus (2 , ChronoUnit .MINUTES );
120120
121- // Use computeIfPresent for atomic check-and-remove to avoid TOCTOU race condition
122- // where inUse could be incremented between check and removal
123- httpClients .forEach (
124- (uri , entry ) -> {
125- httpClients .computeIfPresent (
126- uri ,
127- (key , currentEntry ) -> {
128- // Atomically check conditions and remove if stale
129- if (currentEntry .inUse .get () != 0 ) {
130- // the client is currently in use
131- return currentEntry ;
132- } else if (!currentEntry .lastUse .isBefore (staleBefore )) {
133- // the client was recently used
134- return currentEntry ;
135- } else {
136- // the client has not been used for a while, remove it from the cache
137- try {
138- currentEntry .httpClient .close ();
139- } catch (Exception ex ) {
140- LOG .log (Level .WARNING , "failed to close a stale httpclient" , ex );
141- }
142- return null ; // removes entry from map
143- }
144- });
121+ // Use removeIf for safe and efficient removal from ConcurrentHashMap
122+ httpClients .entrySet ().removeIf (
123+ entry -> {
124+ CacheEntry cacheEntry = entry .getValue ();
125+ if (cacheEntry .inUse .get () != 0 ) {
126+ // the client is currently in use
127+ return false ;
128+ }
129+ if (!cacheEntry .lastUse .isBefore (staleBefore )) {
130+ // the client was recently used
131+ return false ;
132+ }
133+ // the client has not been used for a while, close and remove it
134+ try {
135+ cacheEntry .httpClient .close ();
136+ } catch (Exception ex ) {
137+ LOG .log (Level .WARNING , "failed to close a stale httpclient" , ex );
138+ }
139+ return true ;
145140 });
146141 };
147142
0 commit comments