浏览代码

add groupTimeInterval

Looly 5 年之前
父节点
当前提交
a302a11483

+ 2 - 0
CHANGELOG.md

@@ -21,6 +21,8 @@
 * 【core   】     ArrayUtil增加shuffle方法(pr#1255@Github)
 * 【core   】     ArrayUtil部分方法分离至PrimitiveArrayUtil
 * 【crypto 】     opt改为otp包(issue#1257@Github)
+* 【cache  】     增加CacheListener(issue#1257@Github)
+* 【core   】     TimeInterval支持分组(issue#1238@Github)
 
 ### Bug修复
 * 【cron   】     修复CronTimer可能死循环的问题(issue#1224@Github)

+ 11 - 1
hutool-cache/src/main/java/cn/hutool/cache/Cache.java

@@ -45,7 +45,6 @@ public interface Cache<K, V> extends Iterable<V>, Serializable {
 	 * @param key     键
 	 * @param object  缓存的对象
 	 * @param timeout 失效时长,单位毫秒
-	 * @see Cache#put(Object, Object, long)
 	 */
 	void put(K key, V object, long timeout);
 
@@ -159,4 +158,15 @@ public interface Cache<K, V> extends Iterable<V>, Serializable {
 	 * @return 是否包含key
 	 */
 	boolean containsKey(K key);
+
+	/**
+	 * 设置监听
+	 *
+	 * @param listener 监听
+	 * @return this
+	 * @since 5.5.2
+	 */
+	default Cache<K, V> setListener(CacheListener<K, V> listener){
+		return this;
+	}
 }

+ 20 - 0
hutool-cache/src/main/java/cn/hutool/cache/CacheListener.java

@@ -0,0 +1,20 @@
+package cn.hutool.cache;
+
+/**
+ * 缓存监听,用于实现缓存操作时的回调监听,例如缓存对象的移除事件等
+ *
+ * @param <K> 缓存键
+ * @param <V> 缓存值
+ * @author looly
+ * @since 5.5.2
+ */
+public interface CacheListener<K, V> {
+
+	/**
+	 * 对象移除回调
+	 *
+	 * @param key          键
+	 * @param cachedObject 被缓存的对象
+	 */
+	void onRemove(K key, V cachedObject);
+}

+ 25 - 3
hutool-cache/src/main/java/cn/hutool/cache/impl/AbstractCache.java

@@ -1,6 +1,7 @@
 package cn.hutool.cache.impl;
 
 import cn.hutool.cache.Cache;
+import cn.hutool.cache.CacheListener;
 import cn.hutool.core.collection.CopiedIter;
 import cn.hutool.core.lang.func.Func0;
 
@@ -51,6 +52,11 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
 	 */
 	protected AtomicLong missCount = new AtomicLong();
 
+	/**
+	 * 缓存监听
+	 */
+	protected CacheListener<K, V> listener;
+
 	// ---------------------------------------------------------------- put start
 	@Override
 	public void put(K key, V object) {
@@ -164,7 +170,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
 
 			if (co.isExpired()) {
 				missCount.getAndIncrement();
-			} else{
+			} else {
 				// 命中
 				hitCount.getAndIncrement();
 				return co.get(isUpdateLastAccess);
@@ -280,13 +286,29 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
 	// ---------------------------------------------------------------- common end
 
 	/**
-	 * 对象移除回调。默认无动作
+	 * 设置监听
+	 *
+	 * @param listener 监听
+	 * @return this
+	 * @since 5.5.2
+	 */
+	public AbstractCache<K, V> setListener(CacheListener<K, V> listener) {
+		this.listener = listener;
+		return this;
+	}
+
+	/**
+	 * 对象移除回调。默认无动作<br>
+	 * 子类可重写此方法用于监听移除事件,如果重写,listener将无效
 	 *
 	 * @param key          键
 	 * @param cachedObject 被缓存的对象
 	 */
 	protected void onRemove(K key, V cachedObject) {
-		// ignore
+		final CacheListener<K, V> listener = this.listener;
+		if (null != listener) {
+			listener.onRemove(key, cachedObject);
+		}
 	}
 
 	/**

+ 6 - 0
hutool-cache/src/test/java/cn/hutool/cache/test/CacheTest.java

@@ -18,6 +18,12 @@ public class CacheTest {
 	@Test
 	public void fifoCacheTest(){
 		Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
+		fifoCache.setListener((key, value)->{
+			// 监听测试,此测试中只有key1被移除,测试是否监听成功
+			Assert.assertEquals("key1", key);
+			Assert.assertEquals("value1", value);
+		});
+
 		fifoCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
 		fifoCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
 		fifoCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);

+ 177 - 0
hutool-core/src/main/java/cn/hutool/core/date/GroupTimeInterval.java

@@ -0,0 +1,177 @@
+package cn.hutool.core.date;
+
+import cn.hutool.core.util.ObjectUtil;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 分组计时器<br>
+ * 计算某几个过程花费的时间,精确到毫秒或纳秒
+ *
+ * @author Looly
+ * @since 5.5.2
+ */
+public class GroupTimeInterval implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	private final boolean isNano;
+	protected final Map<String, Long> groupMap;
+
+	/**
+	 * 构造
+	 *
+	 * @param isNano 是否使用纳秒计数,false则使用毫秒
+	 */
+	public GroupTimeInterval(boolean isNano) {
+		this.isNano = isNano;
+		groupMap = new ConcurrentHashMap<>();
+	}
+
+	/**
+	 * 清空所有定时记录
+	 *
+	 * @return this
+	 */
+	public GroupTimeInterval clear(){
+		this.groupMap.clear();
+		return this;
+	}
+
+	/**
+	 * 开始计时并返回当前时间
+	 *
+	 * @param id 分组ID
+	 * @return 开始计时并返回当前时间
+	 */
+	public long start(String id) {
+		final long time = getTime();
+		this.groupMap.put(id, time);
+		return time;
+	}
+
+	/**
+	 * 重新计时并返回从开始到当前的持续时间秒<br>
+	 * 如果此分组下没有记录,则返回0;
+	 *
+	 * @param id 分组ID
+	 * @return 重新计时并返回从开始到当前的持续时间
+	 */
+	public long intervalRestart(String id) {
+		final long now = getTime();
+		return now - ObjectUtil.defaultIfNull(this.groupMap.put(id, now), now);
+	}
+
+	//----------------------------------------------------------- Interval
+
+	/**
+	 * 从开始到当前的间隔时间(毫秒数)<br>
+	 * 如果使用纳秒计时,返回纳秒差,否则返回毫秒差<br>
+	 * 如果分组下没有开始时间,返回{@code null}
+	 *
+	 * @param id 分组ID
+	 * @return 从开始到当前的间隔时间(毫秒数)
+	 */
+	public long interval(String id) {
+		final Long lastTime = this.groupMap.get(id);
+		if (null == lastTime) {
+			return 0;
+		}
+		return getTime() - lastTime;
+	}
+
+	/**
+	 * 从开始到当前的间隔时间
+	 *
+	 * @param id       分组ID
+	 * @param dateUnit 时间单位
+	 * @return 从开始到当前的间隔时间(毫秒数)
+	 */
+	public long interval(String id, DateUnit dateUnit) {
+		final long intervalMs = isNano ? interval(id) / 1000000L : interval(id);
+		if (DateUnit.MS == dateUnit) {
+			return intervalMs;
+		}
+		return intervalMs / dateUnit.getMillis();
+	}
+
+	/**
+	 * 从开始到当前的间隔时间(毫秒数)
+	 *
+	 * @param id 分组ID
+	 * @return 从开始到当前的间隔时间(毫秒数)
+	 */
+	public long intervalMs(String id) {
+		return interval(id, DateUnit.MS);
+	}
+
+	/**
+	 * 从开始到当前的间隔秒数,取绝对值
+	 *
+	 * @param id 分组ID
+	 * @return 从开始到当前的间隔秒数,取绝对值
+	 */
+	public long intervalSecond(String id) {
+		return interval(id, DateUnit.SECOND);
+	}
+
+	/**
+	 * 从开始到当前的间隔分钟数,取绝对值
+	 *
+	 * @param id 分组ID
+	 * @return 从开始到当前的间隔分钟数,取绝对值
+	 */
+	public long intervalMinute(String id) {
+		return interval(id, DateUnit.MINUTE);
+	}
+
+	/**
+	 * 从开始到当前的间隔小时数,取绝对值
+	 *
+	 * @param id 分组ID
+	 * @return 从开始到当前的间隔小时数,取绝对值
+	 */
+	public long intervalHour(String id) {
+		return interval(id, DateUnit.HOUR);
+	}
+
+	/**
+	 * 从开始到当前的间隔天数,取绝对值
+	 *
+	 * @param id 分组ID
+	 * @return 从开始到当前的间隔天数,取绝对值
+	 */
+	public long intervalDay(String id) {
+		return interval(id, DateUnit.DAY);
+	}
+
+	/**
+	 * 从开始到当前的间隔周数,取绝对值
+	 *
+	 * @param id 分组ID
+	 * @return 从开始到当前的间隔周数,取绝对值
+	 */
+	public long intervalWeek(String id) {
+		return interval(id, DateUnit.WEEK);
+	}
+
+	/**
+	 * 从开始到当前的间隔时间(毫秒数),返回XX天XX小时XX分XX秒XX毫秒
+	 *
+	 * @param id 分组ID
+	 * @return 从开始到当前的间隔时间(毫秒数)
+	 */
+	public String intervalPretty(String id) {
+		return DateUtil.formatBetween(intervalMs(id));
+	}
+
+	/**
+	 * 获取时间的毫秒或纳秒数,纳秒非时间戳
+	 *
+	 * @return 时间
+	 */
+	private long getTime() {
+		return this.isNano ? System.nanoTime() : System.currentTimeMillis();
+	}
+}

+ 17 - 31
hutool-core/src/main/java/cn/hutool/core/date/TimeInterval.java

@@ -1,6 +1,6 @@
 package cn.hutool.core.date;
 
-import java.io.Serializable;
+import cn.hutool.core.util.StrUtil;
 
 /**
  * 计时器<br>
@@ -8,11 +8,9 @@ import java.io.Serializable;
  *
  * @author Looly
  */
-public class TimeInterval implements Serializable {
+public class TimeInterval extends GroupTimeInterval {
 	private static final long serialVersionUID = 1L;
-
-	private long time;
-	private final boolean isNano;
+	private static final String DEFAULT_ID = StrUtil.EMPTY;
 
 	/**
 	 * 构造,默认使用毫秒计数
@@ -23,10 +21,11 @@ public class TimeInterval implements Serializable {
 
 	/**
 	 * 构造
+	 *
 	 * @param isNano 是否使用纳秒计数,false则使用毫秒
 	 */
 	public TimeInterval(boolean isNano) {
-		this.isNano = isNano;
+		super(isNano);
 		start();
 	}
 
@@ -34,28 +33,25 @@ public class TimeInterval implements Serializable {
 	 * @return 开始计时并返回当前时间
 	 */
 	public long start() {
-		time = getTime(isNano);
-		return time;
+		return start(DEFAULT_ID);
 	}
 
 	/**
 	 * @return 重新计时并返回从开始到当前的持续时间
 	 */
 	public long intervalRestart() {
-		long now = getTime(isNano);
-		long d = now - time;
-		time = now;
-		return d;
+		return intervalRestart(DEFAULT_ID);
 	}
 
 	/**
 	 * 重新开始计算时间(重置开始时间)
 	 *
 	 * @return this
+	 * @see #start()
 	 * @since 3.0.1
 	 */
 	public TimeInterval restart() {
-		time = getTime(isNano);
+		start(DEFAULT_ID);
 		return this;
 	}
 
@@ -68,7 +64,7 @@ public class TimeInterval implements Serializable {
 	 * @return 从开始到当前的间隔时间(毫秒数)
 	 */
 	public long interval() {
-		return getTime(isNano) - time;
+		return interval(DEFAULT_ID);
 	}
 
 	/**
@@ -78,7 +74,7 @@ public class TimeInterval implements Serializable {
 	 * @since 4.6.7
 	 */
 	public String intervalPretty() {
-		return DateUtil.formatBetween(intervalMs());
+		return intervalPretty(DEFAULT_ID);
 	}
 
 	/**
@@ -87,7 +83,7 @@ public class TimeInterval implements Serializable {
 	 * @return 从开始到当前的间隔时间(毫秒数)
 	 */
 	public long intervalMs() {
-		return isNano ? interval() / 1000000L : interval();
+		return intervalMs(DEFAULT_ID);
 	}
 
 	/**
@@ -96,7 +92,7 @@ public class TimeInterval implements Serializable {
 	 * @return 从开始到当前的间隔秒数,取绝对值
 	 */
 	public long intervalSecond() {
-		return intervalMs() / DateUnit.SECOND.getMillis();
+		return intervalSecond(DEFAULT_ID);
 	}
 
 	/**
@@ -105,7 +101,7 @@ public class TimeInterval implements Serializable {
 	 * @return 从开始到当前的间隔分钟数,取绝对值
 	 */
 	public long intervalMinute() {
-		return intervalMs() / DateUnit.MINUTE.getMillis();
+		return intervalMinute(DEFAULT_ID);
 	}
 
 	/**
@@ -114,7 +110,7 @@ public class TimeInterval implements Serializable {
 	 * @return 从开始到当前的间隔小时数,取绝对值
 	 */
 	public long intervalHour() {
-		return intervalMs() / DateUnit.HOUR.getMillis();
+		return intervalHour(DEFAULT_ID);
 	}
 
 	/**
@@ -123,7 +119,7 @@ public class TimeInterval implements Serializable {
 	 * @return 从开始到当前的间隔天数,取绝对值
 	 */
 	public long intervalDay() {
-		return intervalMs() / DateUnit.DAY.getMillis();
+		return intervalDay(DEFAULT_ID);
 	}
 
 	/**
@@ -132,16 +128,6 @@ public class TimeInterval implements Serializable {
 	 * @return 从开始到当前的间隔周数,取绝对值
 	 */
 	public long intervalWeek() {
-		return intervalMs() / DateUnit.WEEK.getMillis();
-	}
-
-	/**
-	 * 获取时间的毫秒或纳秒数,纳秒非时间戳
-	 *
-	 * @param isNano 是否为高精度时间
-	 * @return 时间
-	 */
-	private static long getTime(boolean isNano) {
-		return isNano ? System.nanoTime() : System.currentTimeMillis();
+		return intervalWeek(DEFAULT_ID);
 	}
 }

+ 4 - 0
hutool-core/src/main/java/cn/hutool/core/thread/ConcurrencyTester.java

@@ -21,6 +21,10 @@ public class ConcurrencyTester {
 	private final TimeInterval timeInterval;
 	private long interval;
 
+	/**
+	 * 构造
+	 * @param threadSize 线程数
+	 */
 	public ConcurrencyTester(int threadSize) {
 		this.sf = new SyncFinisher(threadSize);
 		this.timeInterval = new TimeInterval();

+ 20 - 0
hutool-core/src/test/java/cn/hutool/core/date/TimeIntervalTest.java

@@ -0,0 +1,20 @@
+package cn.hutool.core.date;
+
+import cn.hutool.core.lang.Console;
+import cn.hutool.core.thread.ThreadUtil;
+import org.junit.Test;
+
+public class TimeIntervalTest {
+	@Test
+	public void intervalGroupTest(){
+		final TimeInterval timer = new TimeInterval();
+		timer.start("1");
+		ThreadUtil.sleep(800);
+		timer.start("2");
+		ThreadUtil.sleep(900);
+
+
+		Console.log("Timer 1 took {} ms", timer.intervalMs("1"));
+		Console.log("Timer 2 took {} ms", timer.intervalMs("2"));
+	}
+}