防止缓存击穿的伪代码(单个应用,同时只允许一个线程穿透缓存)

試著忘記壹切 提交于 2019-12-27 19:22:41

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

package liurong.driver.cache;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 
 * @desc 缓存模板
 *
 * @author liurong
 *
 * @date 2019年12月27日
 */
public abstract class CacheTemplate<T> {

	private static final ConcurrentHashMap<String, ReentrantLock> CACHE_LOCK = new ConcurrentHashMap<String, ReentrantLock>();

	/**
	 * 获取数据(内部已经防止缓存击穿)
	 * 
	 * @param key
	 * @return
	 */
	public T getData(String key) {
		T cacheData = getCache(key);
		if (cacheData == null) {
			cacheData = get(key);
		}
		return cacheData;
	}

	/**
	 * 防止缓存击穿
	 * 
	 * @param key
	 * @return
	 */
	public T get(String key) {
		ReentrantLock LOCK = getLock(key);
		if (LOCK.tryLock()) {// 只允许一个线程穿透缓存,查询DB
			try {
				T cache = getCache(key);// 再次查询缓存,提高缓存命中率
				if (cache == null) {
					// 设置缓存
					setCache(key, getDB(key));
				} else {
					return cache;
				}
			} finally {
				LOCK.unlock();

			}
		}

		try {
			LOCK.lock();
			return getCache(key);
		} finally {
			LOCK.unlock();
			// 清空锁
			CACHE_LOCK.remove(key);
		}
	}

	/**
	 * 获取锁
	 * 
	 * @param key
	 * @return
	 */
	private static ReentrantLock getLock(String key) {
		ReentrantLock LOCK = CACHE_LOCK.putIfAbsent(key, new ReentrantLock());
		if (LOCK == null) {// 第一次设置必然为null,所以这里防止第一次获取为null
			LOCK = CACHE_LOCK.get(key);
		}
		return LOCK;
	}

	/**
	 * 设置缓存
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public abstract void setCache(String key, T value);

	/**
	 * 从缓存获取
	 * 
	 * @param key
	 * @return
	 */
	public abstract T getCache(String key);

	/**
	 * 从DB获取
	 * 
	 * @param key
	 * @return
	 */
	public abstract T getDB(String key);
}

package liurong.driver.cache;

import java.util.concurrent.ConcurrentHashMap;

public class AddressCache extends CacheTemplate<String> {

	// 这里可以使本地缓存,也可以是nosql缓存
	public static final ConcurrentHashMap<String, String> CACHE_DATA = new ConcurrentHashMap<String, String>();

	@Override
	public void setCache(String key, String value) {
		CACHE_DATA.put(key, value);
	}

	@Override
	public String getCache(String key) {
		return CACHE_DATA.get(key);
	}

	@Override
	public String getDB(String key) {
		return "自己实现从DB获取数据";
	}

}
package liurong.driver.cache;

public class AddressCacheTest {
	public static AddressCache addressCache = new AddressCache();

	static {
		addressCache.setCache("1", "1");
		addressCache.setCache("2", "2");
		addressCache.setCache("3", "3");
	}

	public static void main(String[] args) {
		System.out.println(addressCache.getData("1"));
		System.out.println(addressCache.getData("abc"));
	}
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!