Storing recent search phrases

Posted on


I have a search on a very simple spring-powered website and I want to display 10 recent inputs:

import java.util.Collection;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Component;

public class RecentPhrases implements DisposableBean {
    static final int SIZE = 10;
    private final ExecutorService offeringService = Executors.newFixedThreadPool(1);
    private final ConcurrentMap<String, Long> phrases = new ConcurrentHashMap<>();

    public void destroy() {

    public void offer(final String phrase) {
        offeringService.execute(() -> {
            phrases.put(phrase, System.currentTimeMillis());
            while (phrases.size() > SIZE) {
                long oldestAge = Long.MAX_VALUE;
                String oldestPhrase = null;
                for (Entry<String, Long> entry : phrases.entrySet()) {
                    if (entry.getValue() < oldestAge) {
                        oldestAge = entry.getValue();
                        oldestPhrase = entry.getKey();

    public Collection<String> getRecent() {
        return phrases.keySet();


Is there some simpler solution that will be lightweight enough to not update the underlying collection in a separate thread?


A LinkedHashSet would be simpler:

  • When the size reaches the limit, simply remove the first entry, no need to iterate
  • When adding an entry, if it already exists, you’d have to reinsert it to update the order: remove and then add
  • No more need to worry about the time of insert

Another advantage of this method is that the entries will be naturally ordered. In your current solution they are unordered, which could appear odd to users. This is not a big advantage though, because you could easily sort before returning the collection.

Instead of oldestAge and oldestPhrase, you could use oldestEntry (initialized e.g. by phrases.entrySet().iterator().get()) as save a line or two.

A List (either ArrayList or LinkedList) would be about equally fast if not faster than the Set as long as the number of entries is at most 10. All you need is

if (phrases.size() > SIZE) {

The correct order is maintained and the speed is probably better for such small collections.

I would not use another thread as its overhead may be comparable to what you’re doing.

Leave a Reply

Your email address will not be published. Required fields are marked *