在 Java 多线程编程里,合理运用全局变量缓存数据,能有效优化性能、提升效率。本文将为你详细介绍三种常见的实现方式,帮你应对不同场景下的缓存需求。
一、基础实现:HashMap + 手动锁
(一)场景需求
当需要简单的缓存结构,且需自主控制线程安全时,可采用 HashMap
配合手动加锁的方式。适用于对缓存逻辑有定制化需求,或需深入理解线程安全控制的场景。
(二)代码示例
java
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
public class GlobalVariableCacheExample1 {
// 定义全局缓存,用 HashMap 存储数据
private static Map<String, Object> cache = new HashMap<>();
// 可重入锁,保障多线程下读写安全
private static final ReentrantLock lock = new ReentrantLock();
// 从缓存获取数据
public static Object getFromCache(String key) {
lock.lock();
try {
return cache.get(key);
} finally {
lock.unlock();
}
}
// 向缓存存入数据
public static void putIntoCache(String key, Object value) {
lock.lock();
try {
cache.put(key, value);
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
// 模拟多线程操作缓存
Thread thread1 = new Thread(() -> {
putIntoCache("key1", "value1");
System.out.println("Thread1: " + getFromCache("key1"));
});
Thread thread2 = new Thread(() -> {
putIntoCache("key2", "value2");
System.out.println("Thread2: " + getFromCache("key2"));
});
thread1.start();
thread2.start();
}
}
(三)实现原理与要点
- 线程安全保障 :借助
ReentrantLock
,在读写缓存的关键代码段加锁、解锁,确保同一时刻只有一个线程能操作缓存,避免多线程并发冲突。 - 使用注意 :加锁、解锁需在
try-finally
块中,保证锁能释放,防止死锁。不过,手动加锁会一定程度增加代码复杂度与执行开销。
二、高效并发:ConcurrentHashMap
(一)场景需求
若追求简洁且高效的线程安全缓存,ConcurrentHashMap
是首选。它内部通过分段锁机制,在多线程高并发场景下,能有效提升读写效率,减少线程阻塞。适用于对性能要求较高的缓存场景。
(二)代码示例
java
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class GlobalVariableCacheExample2 {
// 线程安全的 ConcurrentHashMap 作为缓存
private static Map<String, Object> cache = new ConcurrentHashMap<>();
// 获取缓存数据,直接调用内置方法
public static Object getFromCache(String key) {
return cache.get(key);
}
// 存入缓存数据,调用内置方法
public static void putIntoCache(String key, Object value) {
cache.put(key, value);
}
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
putIntoCache("key1", "value1");
System.out.println("Thread1: " + getFromCache("key1"));
});
Thread thread2 = new Thread(() -> {
putIntoCache("key2", "value2");
System.out.println("Thread2: " + getFromCache("key2"));
});
thread1.start();
thread2.start();
}
}
(三)实现原理与要点
- 线程安全机制 :
ConcurrentHashMap
内部采用分段锁,把数据分成多个段,线程操作不同段时互不干扰,大幅提升并发性能。 - 优势 :无需手动加锁,代码简洁;并发场景下,比
HashMap + 锁
效率更高,减少线程等待时间。
三、功能增强:Guava Cache
(一)场景需求
当缓存需更丰富的功能,如设置缓存容量上限、过期时间、自动加载数据等,Guava Cache
能满足需求。适用于对缓存管理有精细化要求的业务场景。
(二)依赖配置(Maven)
在项目 pom.xml
中添加 Guava 依赖:
XML
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
(三)代码示例
java
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class GlobalVariableCacheExample3 {
// 构建 Guava Cache,配置容量、过期时间等
private static LoadingCache<String, Object> cache = CacheBuilder.newBuilder()
.maximumSize(100) // 缓存最大容量
.expireAfterWrite(10, TimeUnit.MINUTES) // 写入后 10 分钟过期
.build(new CacheLoader<String, Object>() {
@Override
public Object load(String key) throws Exception {
// 缓存未命中时,加载数据的逻辑,这里简单返回 null
return null;
}
});
// 获取缓存数据,处理可能的异常
public static Object getFromCache(String key) {
try {
return cache.get(key);
} catch (ExecutionException e) {
e.printStackTrace();
return null;
}
}
// 存入缓存数据
public static void putIntoCache(String key, Object value) {
cache.put(key, value);
}
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
putIntoCache("key1", "value1");
System.out.println("Thread1: " + getFromCache("key1"));
});
Thread thread2 = new Thread(() -> {
putIntoCache("key2", "value2");
System.out.println("Thread2: " + getFromCache("key2"));
});
thread1.start();
thread2.start();
}
}
(四)实现原理与要点
- 缓存配置 :通过
CacheBuilder
配置缓存参数,如最大容量、过期策略,灵活管控缓存资源。 - 自动加载 :
CacheLoader
实现缓存未命中时的数据加载逻辑,让缓存使用更智能。 - 异常处理 :
get
方法可能抛出ExecutionException
,需捕获并处理,保障程序健壮性。
四、三种方式对比与选型建议
实现方式 | 线程安全保障 | 功能丰富度 | 代码复杂度 | 适用场景 |
---|---|---|---|---|
HashMap + 手动锁 | 手动加锁控制 | 基础 | 较高 | 需深度定制锁逻辑的场景 |
ConcurrentHashMap | 内部分段锁 | 基础 | 低 | 高并发、追求简洁高效的场景 |
Guava Cache | 内部机制保障 | 丰富 | 中等 | 需精细化缓存管理的场景 |
根据项目实际需求,若追求简单高效,选 ConcurrentHashMap
;需定制锁逻辑,用 HashMap + 手动锁
;要复杂缓存策略,就选 Guava Cache
。合理运用这些方式,让多线程缓存助力程序性能提升!