How to Choose and Implement a High‑Performance Local Cache in Java

This article explains why a first‑level local cache is essential for high‑performance services, outlines required cache features, compares four Java implementations (ConcurrentHashMap, Guava, Caffeine, Encache), and provides solutions for consistency, hit‑rate improvement, and technology selection, concluding that Caffeine offers the best performance.

dbaplus Community
dbaplus Community
dbaplus Community
How to Choose and Implement a High‑Performance Local Cache in Java

Background

In high‑performance service architectures, caching is essential. Remote caches such as Redis or Memcached are commonly used as a second‑level cache, but in some scenarios a first‑level local cache can further reduce latency and lower database pressure.

Cache architecture diagram
Cache architecture diagram

Why Use a Local Cache

Local memory access is extremely fast, suitable for data with low change frequency and relaxed real‑time requirements.

Reduces network I/O and latency by avoiding remote cache calls.

Required Features of a Local Cache

Store, read and write operations.

Thread‑safe atomic operations (e.g., ConcurrentHashMap).

Maximum size limit with eviction policies such as LRU or LFU.

Expiration strategies (time‑based, lazy, periodic).

Persistence support.

Statistics and monitoring.

Local Cache Implementation Options

1. ConcurrentHashMap

Simple implementation without third‑party dependencies; suitable for very basic scenarios but lacks advanced features like eviction, expiration, and statistics.

2. Guava Cache

Google’s Guava library provides a mature cache with maximum size, expiration, statistics, and LRU eviction.

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>31.1-jre</version>
</dependency>

@Slf4j
public class GuavaCacheTest {
    public static void main(String[] args) throws ExecutionException {
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .initialCapacity(5)               // initial capacity
                .maximumSize(10)                  // max entries, evict LRU
                .expireAfterWrite(60, TimeUnit.SECONDS) // expiration
                .build();

        String orderId = String.valueOf(123456789);
        String orderInfo = cache.get(orderId, () -> getInfo(orderId));
        log.info("orderInfo = {}", orderInfo);
    }

    private static String getInfo(String orderId) {
        log.info("get data from redis");
        log.info("get data from mysql");
        return String.format("{orderId=%s}", orderId);
    }
}

3. Caffeine

Caffeine is a Java‑8‑based cache that uses the W‑TinyLFU algorithm, offering near‑optimal performance and a feature set similar to Guava.

<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
  <version>2.9.3</version>
</dependency>

@Slf4j
public class CaffeineTest {
    public static void main(String[] args) {
        Cache<String, String> cache = Caffeine.newBuilder()
                .initialCapacity(5)
                .maximumSize(10)                     // evict when full
                .expireAfterWrite(60, TimeUnit.SECONDS)
                .build();

        String orderId = String.valueOf(123456789);
        String orderInfo = cache.get(orderId, key -> getInfo(key));
        System.out.println(orderInfo);
    }

    private static String getInfo(String orderId) {
        log.info("get data from redis");
        log.info("get data from mysql");
        return String.format("{orderId=%s}", orderId);
    }
}

4. Encache (Ehcache)

Encache (Ehcache) offers richer capabilities such as multiple eviction algorithms, heap/off‑heap/disk storage, and clustering support.

<dependency>
  <groupId>org.ehcache</groupId>
  <artifactId>ehcache</artifactId>
  <version>3.9.7</version>
</dependency>

@Slf4j
public class EhcacheTest {
    private static final String ORDER_CACHE = "orderCache";

    public static void main(String[] args) {
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                .withCache(ORDER_CACHE,
                        CacheConfigurationBuilder.newCacheConfigurationBuilder(
                                String.class, String.class, ResourcePoolsBuilder.heap(20)))
                .build(true);

        Cache<String, String> cache = cacheManager.getCache(ORDER_CACHE, String.class, String.class);
        String orderId = String.valueOf(123456789);
        String orderInfo = cache.get(orderId);
        if (StrUtil.isBlank(orderInfo)) {
            orderInfo = getInfo(orderId);
            cache.put(orderId, orderInfo);
        }
        log.info("orderInfo = {}", orderInfo);
    }

    private static String getInfo(String orderId) {
        log.info("get data from redis");
        log.info("get data from mysql");
        return String.format("{orderId=%s}", orderId);
    }
}

Local Cache Problems and Solutions

1. Consistency

Local caches must stay consistent with the database and remote cache. Common solutions include broadcasting invalidation messages via a message queue (MQ) or using Canal to capture MySQL binlog changes and propagate them to caches.

Consistency solution diagram
Consistency solution diagram

2. Improving Hit Rate

Set appropriate expiration times, choose suitable eviction algorithms, and optimize data layout to increase the probability that requested data is found in the local cache.

3. Technical Selection

Ease of use: Guava Cache, Caffeine, and Encache all provide straightforward integration.

Functionality: Guava and Caffeine support heap‑only caches; Encache adds off‑heap, disk persistence, and clustering.

Performance: Benchmarks show Caffeine > Guava > Encache.

Considering ease of use, feature set, and performance, Caffeine is recommended as the primary local cache, combined with Redis or Memcached as a second‑level distributed cache to achieve a robust multi‑level caching architecture.

Performance comparison diagram
Performance comparison diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaCaffeineGuavalocal cacheEhcache
dbaplus Community
Written by

dbaplus Community

Enterprise-level professional community for Database, BigData, and AIOps. Daily original articles, weekly online tech talks, monthly offline salons, and quarterly XCOPS&DAMS conferences—delivered by industry experts.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.