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

org.tio.utils.cache.StampedCache Maven / Gradle / Ivy

There is a newer version: 1.0.8
Show newest version
package org.tio.utils.cache;

import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.locks.StampedLock;

/**
 * 使用{@link StampedLock}保护的缓存,使用读写乐观锁
 *
 * @param  键类型
 * @param  值类型
 * @author looly
 */
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();

	StampedCache(Map> cacheMap, int capacity, long timeout) {
		super(cacheMap, capacity, timeout);
	}

	@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) {
		final long stamp = lock.readLock();
		try {
			// 不存在或已移除
			final CacheObj co = getWithoutLock(key);
			if (co == null) {
				return false;
			}
			if (!co.isExpired()) {
				// 命中
				return true;
			}
		} finally {
			lock.unlockRead(stamp);
		}
		// 过期
		remove(key, true);
		return false;
	}

	@Override
	public V get(K key, boolean isUpdateLastAccess) {
		// 尝试读取缓存,使用乐观读锁
		long stamp = lock.tryOptimisticRead();
		CacheObj co = getWithoutLock(key);
		if (!lock.validate(stamp)) {
			// 有写线程修改了此对象,悲观读
			stamp = lock.readLock();
			try {
				co = getWithoutLock(key);
			} finally {
				lock.unlockRead(stamp);
			}
		}
		// 未命中
		if (null == co) {
			missCount.increment();
			return null;
		} else if (!co.isExpired()) {
			hitCount.increment();
			return co.get(isUpdateLastAccess);
		}
		// 过期,既不算命中也不算非命中
		remove(key, true);
		return null;
	}

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

	@Override
	public void remove(K key) {
		remove(key, false);
	}

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

	/**
	 * 移除key对应的对象
	 *
	 * @param key           键
	 * @param withMissCount 是否计数丢失数
	 */
	private void remove(K key, boolean withMissCount) {
		final long stamp = lock.writeLock();
		CacheObj co;
		try {
			co = removeWithoutLock(key, withMissCount);
		} finally {
			lock.unlockWrite(stamp);
		}
		if (null != co) {
			onRemove(co.key, co.obj);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy