写点什么

一种线程安全的缓存工具实现方式

  • 2025-01-22
    福建
  • 本文字数:1205 字

    阅读完需:约 4 分钟

前言


在多线程环境下,缓存是一个常见的性能优化手段。然而,实现一个线程安全的缓存并不容易,尤其是在高并发场景下,如何避免重复计算、保证数据一致性是一个挑战。最近在读《Java 并发编程实战》时,书中提到了一种基于 ConcurrentHashMap 和 FutureTask 的线程安全缓存实现方式,今天就来分享记录一下。


实现背景


在高并发场景中,缓存的核心作用是避免重复计算。比如,某个计算任务非常耗时,如果多个线程同时请求相同的数据,我们希望只计算一次,后续请求直接使用缓存结果。然而,实现这样的缓存工具需要考虑以下几个问题:


线程安全:多个线程可能同时访问缓存,如何避免竞态条件?避免重复计算:如何确保相同的计算任务只执行一次?异常处理:如果计算任务抛出异常,如何清理缓存并通知调用方?


实现代码


public interface Computable<A, V> {    V compute(A arg) throws InterruptedException;}
复制代码


import java.util.Map;import java.util.concurrent.*;
public class CacheUtils<A, V> implements Computable<A, V> { private final Map<A, Future<V>> cache = new ConcurrentHashMap<>(); private final Computable<A, V> computable;
public CacheUtils(Computable<A, V> computable) { this.computable = computable; }
@Override public V compute(A arg) throws InterruptedException { while (true) { Future<V> future = cache.get(arg); if (future == null) { Callable<V> eval = () -> computable.compute(arg); FutureTask<V> futureTask = new FutureTask<>(eval); future = cache.putIfAbsent(arg, futureTask); if (future == null) { future = futureTask; futureTask.run(); } } try { return future.get(); } catch (CancellationException e) { // 如果任务被取消,移除缓存中的 Future cache.remove(arg, future); } catch (ExecutionException e) { // 如果计算任务抛出异常,移除缓存中的 Future 并抛出异常 cache.remove(arg, future); throw new RuntimeException("Computation failed for argument: " + arg, e.getCause()); } } }}
复制代码


实现思路说明


使用 ConcurrentHashMap 中 putIfAbsent 方法来保证,同一时刻只能有一个线程可以将 FutureTask 放入缓存,从而避免相同任务的重复计算;当计算任务发生异常时,可以及时抛出错误/取消缓存结果。


文章转载自:帅气的涛啊

原文链接:https://www.cnblogs.com/handsometaoa/p/18682740

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
一种线程安全的缓存工具实现方式_线程_不在线第一只蜗牛_InfoQ写作社区