All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.hutool.cache.impl.StampedCache Maven / Gradle / Ivy

The newest version!
package cn.hutool.cache.impl;

import cn.hutool.core.collection.CopiedIter;

import java.util.Iterator;
import java.util.concurrent.locks.StampedLock;

/**
 * 使用{@link StampedLock}保护的缓存,使用读写乐观锁
 *
 * @param  键类型
 * @param  值类型
 * @author looly
 * @since 5.7.15
 * @deprecated Map使用StampedLock可能造成数据不一致甚至Map循环调用,此缓存废弃
 */
@Deprecated
public abstract class StampedCache extends AbstractCache {
	private static final long serialVersionUID = 1L;

	// 乐观锁,此处使用乐观锁解决读多写少的场景
	// get时乐观读,再检查是否修改,修改则转入悲观读重新读一遍,可以有效解决在写时阻塞大量读操作的情况。
	// see: https://www.cnblogs.com/jiagoushijuzi/p/13721319.html
	protected final StampedLock lock = new StampedLock();

	@Override
	public void put(K key, V object, long timeout) {
		final long stamp = lock.writeLock();
		try {
			putWithoutLock(key, object, timeout);
		} finally {
			lock.unlockWrite(stamp);
		}
	}

	@Override
	public boolean containsKey(K key) {
		return null != get(key, false, false);
	}

	@Override
	public V get(K key, boolean isUpdateLastAccess) {
		return get(key, isUpdateLastAccess, true);
	}

	@Override
	public Iterator> cacheObjIterator() {
		CopiedIter> copiedIterator;
		final long stamp = lock.readLock();
		try {
			copiedIterator = CopiedIter.copyOf(cacheObjIter());
		} finally {
			lock.unlockRead(stamp);
		}
		return new CacheObjIterator<>(copiedIterator);
	}

	@Override
	public final int prune() {
		final long stamp = lock.writeLock();
		try {
			return pruneCache();
		} finally {
			lock.unlockWrite(stamp);
		}
	}

	@Override
	public void remove(K key) {
		final long stamp = lock.writeLock();
		CacheObj co;
		try {
			co = removeWithoutLock(key);
		} finally {
			lock.unlockWrite(stamp);
		}
		if (null != co) {
			onRemove(co.key, co.obj);
		}
	}

	@Override
	public void clear() {
		final long stamp = lock.writeLock();
		try {
			cacheMap.clear();
		} finally {
			lock.unlockWrite(stamp);
		}
	}

	/**
	 * 获取值,使用乐观锁,但是此方法可能导致读取脏数据,但对于缓存业务可容忍。情况如下:
	 * 
	 *     1. 读取时无写入,不冲突,直接获取值
	 *     2. 读取时无写入,但是乐观读时触发了并发异常,此时获取同步锁,获取新值
	 *     4. 读取时有写入,此时获取同步锁,获取新值
	 * 
* * @param key 键 * @param isUpdateLastAccess 是否更新最后修改时间 * @param isUpdateCount 是否更新命中数,get时更新,contains时不更新 * @return 值或null */ private V get(K key, boolean isUpdateLastAccess, boolean isUpdateCount) { // 尝试读取缓存,使用乐观读锁 CacheObj co = null; long stamp = lock.tryOptimisticRead(); boolean isReadError = true; if(lock.validate(stamp)){ try{ // 乐观读,可能读取脏数据,在缓存中可容忍,分两种情况 // 1. 读取时无线程写入 // 2. 读取时有线程写入,导致数据不一致,此时读取未更新的缓存值 co = getWithoutLock(key); isReadError = false; } catch (final Exception ignore){ // ignore } } if(isReadError){ // 转换为悲观读 // 原因可能为无锁读时触发并发异常,或者锁被占(正在写) stamp = lock.readLock(); try { co = getWithoutLock(key); } finally { lock.unlockRead(stamp); } } // 未命中 if (null == co) { if (isUpdateCount) { missCount.increment(); } return null; } else if (false == co.isExpired()) { if (isUpdateCount) { hitCount.increment(); } return co.get(isUpdateLastAccess); } // 悲观锁,二次检查 return getOrRemoveExpired(key, isUpdateCount); } /** * 同步获取值,如果过期则移除之 * * @param key 键 * @param isUpdateCount 是否更新命中数,get时更新,contains时不更新 * @return 有效值或null */ private V getOrRemoveExpired(K key, boolean isUpdateCount) { final long stamp = lock.writeLock(); CacheObj co; try { co = getWithoutLock(key); if (null == co) { return null; } if (false == co.isExpired()) { // 首先尝试获取值,如果值存在且有效,返回之 if (isUpdateCount) { hitCount.increment(); } return co.getValue(); } // 无效移除 co = removeWithoutLock(key); } finally { lock.unlockWrite(stamp); } if (null != co) { onRemove(co.key, co.obj); } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy