From 831a95154e35018b48a8a1dd4a434ca65a78c5e4 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Sun, 22 Mar 2020 21:38:53 +0100 Subject: [PATCH] Polish ConcurrentLruCache This commit improves the performance of the `ConcurrentLruCache` and applies a consistent style to the code: * separating read/write locks into different variables does not help performance, so this change is reverted * apply a consistent style for read/write locks and try/cactch calls * the reordering of recently used keys is only done when the cache is full Fixes gh-24671 --- .../springframework/util/MimeTypeUtils.java | 42 +++++++------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java index 6d6f061b457..89609925bc7 100644 --- a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java +++ b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,6 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; @@ -421,9 +420,7 @@ public abstract class MimeTypeUtils { private final ConcurrentHashMap cache = new ConcurrentHashMap<>(); - private final Lock readLock; - - private final Lock writeLock; + private final ReadWriteLock lock; private final Function generator; @@ -434,43 +431,36 @@ public abstract class MimeTypeUtils { Assert.notNull(generator, "Generator function should not be null"); this.maxSize = maxSize; this.generator = generator; - - ReadWriteLock lock = new ReentrantReadWriteLock(); - this.readLock = lock.readLock(); - this.writeLock = lock.writeLock(); + this.lock = new ReentrantReadWriteLock(); } public V get(K key) { - V cached; - - if ((cached = this.cache.get(key)) != null) { - if (this.size < this.maxSize / 2) { + V cached = this.cache.get(key); + if (cached != null) { + if (this.size < this.maxSize) { return cached; } - + this.lock.readLock().lock(); try { - this.readLock.lock(); - this.queue.add(key); this.queue.remove(key); + this.queue.add(key); return cached; } finally { - this.readLock.unlock(); + this.lock.readLock().unlock(); } } - - this.writeLock.lock(); + this.lock.writeLock().lock(); try { - // retrying in case of concurrent reads on the same key - if ((cached = this.cache.get(key)) != null) { - this.queue.add(key); + // Retrying in case of concurrent reads on the same key + cached = this.cache.get(key); + if (cached != null) { this.queue.remove(key); + this.queue.add(key); return cached; } - // Generate value first, to prevent size inconsistency V value = this.generator.apply(key); - int cacheSize = this.size; if (cacheSize == this.maxSize) { K leastUsed = this.queue.poll(); @@ -479,15 +469,13 @@ public abstract class MimeTypeUtils { cacheSize--; } } - this.queue.add(key); this.cache.put(key, value); this.size = cacheSize + 1; - return value; } finally { - this.writeLock.unlock(); + this.lock.writeLock().unlock(); } } }