利用OsCache实现后端轮循
轮循随处可见,最常用的是APP首页的一些促销活动,一两秒切换一张图片,让前端实现起来也不难。这里说下后端的轮循,实现原理是数组+缓存。将数组放入缓存,指定缓存失效时间,如果是在失效前从缓存中取数据,那么就是老数据,如果是在失效后取,那么就是失效的数据,需要将数组里的元素列表按配置进行重排。
举个例子,轮循时间(缓存失效时间)设置10秒,数组里有3个元素1,2,3,第一次取到的必然是1,2,3,因为缓存里没数据。第二次查询,如果还没到10秒,那么我们还是能从缓存里取到数据,还是1,2,3。一旦超出10秒后查询,缓存取不到数据了,但我们能从异常里取到失效的缓存数据(这时还是1,2,3),按不同的轮循算法对数组重排(比如变成3,1,2),再放入缓存。以此类推,循环往复。
直接看代码输出,再看代码实现:
九月 25, 2018 4:57:32 下午 com.opensymphony.oscache.base.Config loadProperties
信息: OSCache: Getting properties from URL file:/E:/workspace/TeaPot/target/classes/oscache.properties for the default configuration
九月 25, 2018 4:57:32 下午 com.opensymphony.oscache.base.Config loadProperties
信息: OSCache: Properties read {cache.algorithm=com.opensymphony.oscache.base.algorithm.FIFOCache, cache.capacity=100000, cache.memory=true}
九月 25, 2018 4:57:32 下午 com.opensymphony.oscache.general.GeneralCacheAdministrator <init>
信息: Constructed GeneralCacheAdministrator()
九月 25, 2018 4:57:32 下午 com.opensymphony.oscache.general.GeneralCacheAdministrator createCache
信息: Creating new cache
九月 25, 2018 4:57:32 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Enter getCycleData(), key: CYCLEKEY_ ,cycle: [11111, 222222, 333333] ,cycle: CycleTypes{beginDate='1970-01-01 00:00:00', endDate='2999-12-31 23:59:59', cycleNum=1, cycleType=2, isCycle='1', period=10}
九月 25, 2018 4:57:32 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Enter getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:57:32 下午 com.inspur.chinanet.point.cache.OsCache getDataFromOSCacheWithExcepton
警告: The cache time delay is : 2 millisecond.
九月 25, 2018 4:57:32 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Get Data from NeedsRefreshException is :null
九月 25, 2018 4:57:32 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Exit getCycleData(), ids: [11111, 222222, 333333]
[11111, 222222, 333333]
九月 25, 2018 4:57:34 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Enter getCycleData(), key: CYCLEKEY_ ,cycle: [11111, 222222, 333333] ,cycle: CycleTypes{beginDate='1970-01-01 00:00:00', endDate='2999-12-31 23:59:59', cycleNum=1, cycleType=2, isCycle='1', period=10}
九月 25, 2018 4:57:34 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Enter getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:57:34 下午 com.inspur.chinanet.point.cache.OsCache getDataFromOSCacheWithExcepton
警告: The cache time delay is : 2 millisecond.
九月 25, 2018 4:57:34 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Exit getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:57:34 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Get Data from OsCache is :[11111, 222222, 333333]
九月 25, 2018 4:57:34 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After sort Array from OsCache is:[11111, 222222, 333333]
九月 25, 2018 4:57:34 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Exit getCycleData(), ids: [11111, 222222, 333333]
[11111, 222222, 333333]
九月 25, 2018 4:57:44 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Enter getCycleData(), key: CYCLEKEY_ ,cycle: [11111, 222222, 333333] ,cycle: CycleTypes{beginDate='1970-01-01 00:00:00', endDate='2999-12-31 23:59:59', cycleNum=1, cycleType=2, isCycle='1', period=10}
九月 25, 2018 4:57:44 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Enter getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:57:44 下午 com.inspur.chinanet.point.cache.OsCache getDataFromOSCacheWithExcepton
警告: The cache time delay is : 0 millisecond.
九月 25, 2018 4:57:44 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Get Data from NeedsRefreshException is :[11111, 222222, 333333]
九月 25, 2018 4:57:44 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After first sort Array from OsCache is:[11111, 222222, 333333]
九月 25, 2018 4:57:44 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After second sort Array from OsCache is:[333333, 11111, 222222]
九月 25, 2018 4:57:44 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Exit getCycleData(), ids: [333333, 11111, 222222]
[333333, 11111, 222222]
九月 25, 2018 4:57:46 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Enter getCycleData(), key: CYCLEKEY_ ,cycle: [11111, 222222, 333333] ,cycle: CycleTypes{beginDate='1970-01-01 00:00:00', endDate='2999-12-31 23:59:59', cycleNum=1, cycleType=2, isCycle='1', period=10}
九月 25, 2018 4:57:46 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Enter getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:57:46 下午 com.inspur.chinanet.point.cache.OsCache getDataFromOSCacheWithExcepton
警告: The cache time delay is : 0 millisecond.
九月 25, 2018 4:57:46 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Exit getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:57:46 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Get Data from OsCache is :[333333, 11111, 222222]
九月 25, 2018 4:57:46 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After sort Array from OsCache is:[333333, 11111, 222222]
九月 25, 2018 4:57:46 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Exit getCycleData(), ids: [333333, 11111, 222222]
[333333, 11111, 222222]
九月 25, 2018 4:57:56 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Enter getCycleData(), key: CYCLEKEY_ ,cycle: [11111, 222222, 333333] ,cycle: CycleTypes{beginDate='1970-01-01 00:00:00', endDate='2999-12-31 23:59:59', cycleNum=1, cycleType=2, isCycle='1', period=10}
九月 25, 2018 4:57:56 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Enter getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:57:56 下午 com.inspur.chinanet.point.cache.OsCache getDataFromOSCacheWithExcepton
警告: The cache time delay is : 0 millisecond.
九月 25, 2018 4:57:56 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Get Data from NeedsRefreshException is :[333333, 11111, 222222]
九月 25, 2018 4:57:56 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After first sort Array from OsCache is:[333333, 11111, 222222]
九月 25, 2018 4:57:56 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After second sort Array from OsCache is:[222222, 333333, 11111]
九月 25, 2018 4:57:56 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Exit getCycleData(), ids: [222222, 333333, 11111]
[222222, 333333, 11111]
九月 25, 2018 4:58:06 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Enter getCycleData(), key: CYCLEKEY_ ,cycle: [11111, 222222, 444444] ,cycle: CycleTypes{beginDate='1970-01-01 00:00:00', endDate='2999-12-31 23:59:59', cycleNum=1, cycleType=2, isCycle='1', period=10}
九月 25, 2018 4:58:06 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Enter getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:58:06 下午 com.inspur.chinanet.point.cache.OsCache getDataFromOSCacheWithExcepton
警告: The cache time delay is : 0 millisecond.
九月 25, 2018 4:58:06 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Get Data from NeedsRefreshException is :[222222, 333333, 11111]
九月 25, 2018 4:58:06 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After first sort Array from OsCache is:[222222, 11111, 444444]
九月 25, 2018 4:58:06 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After second sort Array from OsCache is:[444444, 222222, 11111]
九月 25, 2018 4:58:06 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Exit getCycleData(), ids: [444444, 222222, 11111]
[444444, 222222, 11111]
九月 25, 2018 4:58:08 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Enter getCycleData(), key: CYCLEKEY_ ,cycle: [11111, 222222, 555555] ,cycle: CycleTypes{beginDate='1970-01-01 00:00:00', endDate='2999-12-31 23:59:59', cycleNum=1, cycleType=2, isCycle='1', period=10}
九月 25, 2018 4:58:08 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Enter getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:58:08 下午 com.inspur.chinanet.point.cache.OsCache getDataFromOSCacheWithExcepton
警告: The cache time delay is : 0 millisecond.
九月 25, 2018 4:58:08 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Exit getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:58:08 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Get Data from OsCache is :[444444, 222222, 11111]
九月 25, 2018 4:58:08 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After sort Array from OsCache is:[222222, 11111, 555555]
九月 25, 2018 4:58:08 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Exit getCycleData(), ids: [222222, 11111, 555555]
[222222, 11111, 555555]
九月 25, 2018 4:58:18 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Enter getCycleData(), key: CYCLEKEY_ ,cycle: [11111, 222222, 555555] ,cycle: CycleTypes{beginDate='1970-01-01 00:00:00', endDate='2999-12-31 23:59:59', cycleNum=1, cycleType=2, isCycle='1', period=10}
九月 25, 2018 4:58:18 下午 com.inspur.chinanet.point.cache.OsCache getDataFromCacheWithRefreshTime
警告: Enter getDataFromCacheWithRefreshTime(), key: CYCLEKEY_ ,refreshTime: 10
九月 25, 2018 4:58:18 下午 com.inspur.chinanet.point.cache.OsCache getDataFromOSCacheWithExcepton
警告: The cache time delay is : 0 millisecond.
九月 25, 2018 4:58:18 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Get Data from NeedsRefreshException is :[444444, 222222, 11111]
九月 25, 2018 4:58:18 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After first sort Array from OsCache is:[222222, 11111, 555555]
九月 25, 2018 4:58:18 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: After second sort Array from OsCache is:[555555, 222222, 11111]
九月 25, 2018 4:58:18 下午 com.inspur.chinanet.point.cache.OsCache getCycleData
警告: Exit getCycleData(), ids: [555555, 222222, 11111]
[555555, 222222, 11111]
轮训bean:
package com.inspur.chinanet.point.bean; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set; /**
* 封装轮训请求入参
*
* @author wulinfeng
* @version C10 2018年9月21日
* @since SDP V300R003C10
*/
public class CycleTypes
{
/** 轮循方式,不轮循 */
public static final int TAG_NO_CYCLE_LOOP = 0; /** 轮循方式,冒泡轮循 */
public static final int TAG_CYCLE_LOOP = 2; /** 轮循方式,随机轮循 */
public static final int TAG_CYCLE_RANDOM = 1; private final static Set<Integer> CYCLE_TYPE_SET = new HashSet<>(); static
{
CYCLE_TYPE_SET.add(TAG_CYCLE_LOOP);
CYCLE_TYPE_SET.add(TAG_CYCLE_RANDOM);
CYCLE_TYPE_SET.add(TAG_NO_CYCLE_LOOP);
} /** 生效日期(格式:yyyy-MM-dd HH:mm:ss) */
private String beginDate; /** 失效日期(格式:yyyy-MM-dd HH:mm:ss) */
private String endDate; /** 轮循个数 */
private int cycleNum; /** 轮循方式 */
private int cycleType; /** 是否支持轮循 */
private String isCycle; /** 轮循周期 */
private int period; public CycleTypes()
{ } public CycleTypes(Map<String, String> params)
{
initCycleInfo(params);
} public String getBeginDate()
{
return beginDate;
} public int getCycleNum()
{
return cycleNum;
} public int getCycleType()
{
return cycleType;
} public String getEndDate()
{
return endDate;
} public String getIsCycle()
{
return isCycle;
} public int getPeriod()
{
return period;
} public void setBeginDate(String beginDate)
{
this.beginDate = beginDate;
} public void setCycleNum(int cycleNum)
{
this.cycleNum = cycleNum;
} public void setCycleType(int cycleType)
{
this.cycleType = cycleType;
} public void setEndDate(String endDate)
{
this.endDate = endDate;
} public void setIsCycle(String isCycle)
{
this.isCycle = isCycle;
} public void setPeriod(int period)
{
this.period = period;
} /**
* 初始化轮训参数
*
* @author wulinfeng
* @param params
*/
public void initCycleInfo(Map<String, String> params)
{
// 开始时间和结束时间,没有配置时不进行限制
beginDate = params.get("cycleBeginDate") == null ? "1970-01-01 00:00:00" : params.get("cycleBeginDate");
endDate = params.get("cycleEndDate") == null ? "2999-12-31 23:59:59" : params.get("cycleEndDate");
isCycle = params.get("isCycle") == null ? "1" : params.get("isCycle"); // 需要同时满足:入参的isCycle为true,开始时间和结束时间格式正确, 并且有效 才开启轮询功能,否则返回不轮询
if (!("1".equals(isCycle) && isEffictive(beginDate, endDate, "yyyy-MM-dd HH:mm:ss")))
{
isCycle = "0";
return;
} // 默认轮询数量2
cycleNum = params.get("cycleNum") != null ? Integer.valueOf(params.get("cycleNum")).intValue() : 2; // 轮循周期, 默认轮询周期十秒钟
period = params.get("cyclePeriod") != null ? Integer.valueOf(params.get("cyclePeriod")).intValue() : 10; cycleType =
params.get("cycleType") != null ? Integer.valueOf(params.get("cycleType")).intValue() : TAG_CYCLE_LOOP;
cycleType = CYCLE_TYPE_SET.contains(cycleType) ? cycleType : TAG_CYCLE_LOOP;
} @Override
public String toString()
{
final StringBuffer sb = new StringBuffer("CycleTypes{");
sb.append("beginDate='").append(beginDate).append('\'');
sb.append(", endDate='").append(endDate).append('\'');
sb.append(", cycleNum=").append(cycleNum);
sb.append(", cycleType=").append(cycleType);
sb.append(", isCycle='").append(isCycle).append('\'');
sb.append(", period=").append(period);
sb.append('}');
return sb.toString();
} /**
* 时间格式校验
*
* @author wulinfeng
* @param date
* @param appointFormat
* @return
*/
private boolean isAppointFormatDate(String date, String dateFormat)
{
if (date != null && dateFormat != null && date.length() == dateFormat.length())
{
try
{
SimpleDateFormat e = new SimpleDateFormat(dateFormat);
e.parse(date);
return Boolean.TRUE.booleanValue();
}
catch (Exception e)
{
e.printStackTrace();
return Boolean.FALSE.booleanValue();
}
}
else
{
return Boolean.FALSE.booleanValue();
}
} /**
* 判断当前时间是否生效
*
* @author wulinfeng
* @param beginDate
* @param endDate
* @param dateFormat
* @return
*/
private boolean isEffictive(String beginDate, String endDate, String dateFormat)
{
// 传入参数为空则设置默认开始时间
if (beginDate == null || beginDate == "")
{
beginDate = "1970-01-01 00:00:00";
}
else
{
// 日期格式不对,返回
if(!isAppointFormatDate(beginDate, dateFormat))
{
return false;
}
} // 传入参数为空则设置默认结束时间
if (endDate == null || endDate == "")
{
endDate = "2999-12-31 23:59:59";
}
else
{
// 日期格式不对,返回
if(!isAppointFormatDate(endDate, dateFormat))
{
return false;
}
} Date now = new Date();
try
{
SimpleDateFormat e = new SimpleDateFormat(dateFormat);
Date begin = e.parse(beginDate);
Date end = e.parse(endDate);
return begin.before(now) && now.before(end);
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
} }
缓存和轮训实现类:
package com.inspur.chinanet.point.cache; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger; import com.inspur.chinanet.point.bean.CycleTypes;
import com.opensymphony.oscache.base.NeedsRefreshException;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;
import com.opensymphony.oscache.web.filter.ExpiresRefreshPolicy; /**
* 本地缓存
*
* @author wulinfeng
* @version C10 2018年3月28日
* @since SDP V300R003C10
*/
public class OsCache extends GeneralCacheAdministrator
{ private static final Logger LOG = Logger.getLogger("OsCache"); /**
* 序列化ID
*/
private static final long serialVersionUID = -3814537980571610987L; /**
* OsCache缓存key
*/
private static final String CACHEKEY = "CYCLEKEY_"; // 缓存命中次数
private AtomicLong hitCount = new AtomicLong(0L); // 总请求次数
private AtomicLong reqCount = new AtomicLong(0L); // 命中率
private double hitRate = 0D; private static OsCache cache = null; /**
* 私有无参构造器
*/
private OsCache()
{
}; /**
* 单例
*/
public static OsCache getInstance()
{
if (cache == null)
{
synchronized (OsCache.class)
{
if (cache == null)
{
cache = new OsCache();
}
}
}
return cache;
} /**
* 从OSCACHE中获取原始缓存数据
*
* @param key 缓存KEY值
* @param refreshTime 失效时间,-1时为永久缓存
* @return 原始缓存数据
*/
public Object get(String key, int refreshTime)
{
reqCount.incrementAndGet();
Object obj = null;
try
{
obj = this.getFromCache(key, refreshTime);
hitCount.incrementAndGet();
}
catch (NeedsRefreshException e)
{
this.cancelUpdate(key);
LOG.warning(e.getMessage());
}
return obj;
} /**
* 放入OSCACHE缓存数据
*
* @param key 缓存KEY值
* @param value Object 内容对象
* @param refreshTime 失效时间,-1时为永久缓存
* @return 原始缓存数据
*/
public void put(String key, Object value, int refreshTime)
{
if (refreshTime == -1)
{
this.putInCache(key, value);
}
else
{
this.putInCache(key, value, new ExpiresRefreshPolicy(refreshTime));
}
} /**
* 从OSCACHE中删除缓存数据
*
* @param key 缓存KEY值
*/
public void remove(String key)
{
this.removeEntry(key);
} /**
* 从OSCACHE中删除所有缓存数据
*
* @param date 预定删除时间
*/
public void removeAll(Date date)
{
if (date == null)
{
this.flushAll();
}
else
{
this.flushAll(date);
}
} /**
* 获取命中率
*
* @author wulinfeng
* @return
*/
public double getHitRate()
{
if (reqCount.longValue() == 0L)
{
return 0;
} hitRate = (double)hitCount.longValue() / reqCount.longValue();
BigDecimal bd = new BigDecimal(hitRate);
bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP); return bd.doubleValue();
} public static void main(String[] args)
throws InterruptedException
{
cache = OsCache.getInstance();
Map<String, String> paramMap = new HashMap<>();
paramMap.put("cycleNum", "1");
paramMap.put("cycleType", "2"); CycleTypes cycleType = new CycleTypes(paramMap);
String[] ids = {"11111", "222222", "333333"}; // 第一波:从oscache取数据,取不到放入缓存
System.out.println(Arrays.toString(cache.getCycleData(CACHEKEY, cycleType, ids))); // 两秒后再取,可以取到缓存数据,展示缓存数据
Thread.sleep(2 * 1000);
System.out.println(Arrays.toString(cache.getCycleData(CACHEKEY, cycleType, ids))); // 有效期10秒过后再次访问,缓存已失效,获取该失效缓存的最后数据,轮循,展示轮循后数据
Thread.sleep(10 * 1000);
System.out.println(Arrays.toString(cache.getCycleData(CACHEKEY, cycleType, ids))); // 两秒后再取,可以取到缓存数据,展示缓存数据
Thread.sleep(2 * 1000);
System.out.println(Arrays.toString(cache.getCycleData(CACHEKEY, cycleType, ids))); // 有效期10秒过后再次访问,缓存已失效,获取失效缓存的最后数据,轮循,展示轮循新数据
Thread.sleep(10 * 1000);
System.out.println(Arrays.toString(cache.getCycleData(CACHEKEY, cycleType, ids))); // 第二波:有效期10秒过后再次访问,缓存已失效,并修改传入数据,获取失效的缓存和传入的最新数据,轮循
Thread.sleep(10 * 1000);
String[] newIds1 = {"11111", "222222", "444444"};
System.out.println(Arrays.toString(cache.getCycleData(CACHEKEY, cycleType, newIds1))); // 两秒后再取,可以取到缓存数据,修改传入数据,替换缓存中的数据
Thread.sleep(2 * 1000);
String[] newIds2 = {"11111", "222222", "555555"};
System.out.println(Arrays.toString(cache.getCycleData(CACHEKEY, cycleType, newIds2))); // 有效期10秒过后再次访问,获取数据并轮循
Thread.sleep(10 * 1000);
System.out.println(Arrays.toString(cache.getCycleData(CACHEKEY, cycleType, newIds2)));
} /**
* 获取轮循数据
*
* @author wulinfeng
* @param key
* @param cycle
* @param strs
* @return
*/
public String[] getCycleData(String key, CycleTypes cycle, String[] strs)
{
// 入口日志
LOG.warning(
"Enter getCycleData(), key: " + key + " ,cycle: " + Arrays.toString(strs) + " ,cycle: " + cycle.toString()); // 不支持轮循,则直接返回,
if ("0".equals(cycle.getIsCycle()))
{
return strs;
} String[] ids = null;
try
{
// 先从缓存中获取数据
ids = (String[])getDataFromCacheWithRefreshTime(key, cycle.getPeriod()); LOG.warning("Get Data from OsCache is :" + Arrays.toString(ids)); // 若传入新数据,过滤掉缓存中的老数据
ids = filterArrays(ids, strs); LOG.warning("After sort Array from OsCache is:" + Arrays.toString(ids));
}
catch (NeedsRefreshException e)
{
// 取上一次轮循的内容,如果为空说明是第一次,则直接赋值传入数据,第一次不需要轮循
ids = (String[])e.getCacheContent();
LOG.warning("Get Data from NeedsRefreshException is :" + Arrays.toString(ids)); if (null == ids || 0 == ids.length)
{
ids = strs;
}
else
{
// 说明有老数据,需要进行数据过滤
ids = filterArrays(ids, strs); LOG.warning("After first sort Array from OsCache is:" + Arrays.toString(ids)); // 轮循过程
ids = getCycleIDsByType(ids, cycle.getCycleNum(), cycle.getCycleType()); LOG.warning("After second sort Array from OsCache is:" + Arrays.toString(ids));
} // 缓存查不到,需要把数据放到缓存中
if (null != ids && 0 != ids.length)
{
put(key, ids, cycle.getPeriod());
}
} LOG.warning("Exit getCycleData(), ids: " + Arrays.toString(ids)); return ids;
} /**
* 根据关键字和失效时间,从OsCache缓存中获取内容
*
* @author wulinfeng
* @param key 缓存key值
* @param refreshTime 单位为秒
* @return
* @throws NeedsRefreshException
*/
private Object getDataFromCacheWithRefreshTime(String key, int refreshTime)
throws NeedsRefreshException
{
// 入口日志
LOG.warning("Enter getDataFromCacheWithRefreshTime(), key: " + key + " ,refreshTime: " + refreshTime); // 入参有效性检查
if ((null == key) || ("".equals(key.trim())))
{
return null;
} // 当有效期小于-1时设置永久缓存
if (refreshTime < -1)
{
refreshTime = -1;
} Object object = null;
try
{
reqCount.incrementAndGet();
if (null == cache)
{
return null;
}
object = this.getDataFromOSCacheWithExcepton(key, refreshTime);
}
catch (NeedsRefreshException e)
{
throw e;
} // 出口日志
LOG.warning("Exit getDataFromCacheWithRefreshTime(), key: " + key + " ,refreshTime: " + refreshTime); return object;
} /**
* 从OSCACHE中获取原始缓存数据
*
* @author wulinfeng
* @param key 缓存KEY值
* @param refreshTime 失效时间
* @return 原始缓存数据
*/
public Object getDataFromOSCacheWithExcepton(String key, int refreshTime)
throws NeedsRefreshException
{
Object obj = null; // 开始时间
long beginTime = System.currentTimeMillis(); try
{
obj = cache.getFromCache(key, refreshTime);
hitCount.incrementAndGet();
}
catch (NeedsRefreshException e)
{
this.cancelUpdate(key);
throw e;
}
finally
{
// 时间间隔
long interval = System.currentTimeMillis() - beginTime; // 记录时延
LOG.warning("The cache time delay is : " + interval + " millisecond.");
}
return obj;
} /**
* 把array1中不存在、array2中存在的数据剔除,替换为array2中的数据
*
* @author wulinfeng
* @param array1
* @param array2
* @return
*/
public static String[] filterArrays(String[] array1, String[] array2)
{
if (null == array1 || 0 == array1.length)
{
return array2;
} if (null == array2 || 0 == array2.length)
{
return null;
} Map<String, Integer> srcMap = new HashMap<String, Integer>(array2.length);
String[] temp = new String[array2.length];
String[] result = new String[array2.length]; for (int i = 0; i < array2.length; i++)
{
srcMap.put(array2[i], Integer.valueOf(i));
temp[i] = array2[i];
} int pos = 0;
for (int i = 0; i < array1.length; i++)
{
Integer index = (Integer)srcMap.remove(array1[i]);
if (null != index)
{
result[pos++] = array1[i];
temp[index.intValue()] = null;
}
} for (int i = 0; ((i < temp.length) && (pos < array2.length)); i++)
{
if (null != temp[i])
{
result[pos++] = temp[i];
}
} return result;
} /**
* 根据轮循类型进行轮循
*
* @author wulinfeng
* @param ids
* @param cycleNum
* @param cycleType
* @return
*/
public static String[] getCycleIDsByType(String[] ids, int cycleNum, int cycleType)
{
String[] cycleIDs = null;
switch (cycleType)
{
// 不轮循
case CycleTypes.TAG_NO_CYCLE_LOOP:
cycleIDs = ids;
break;
// 冒泡轮循
case CycleTypes.TAG_CYCLE_LOOP:
cycleIDs = loopRank(ids, cycleNum);
break;
// 随机轮循
case CycleTypes.TAG_CYCLE_RANDOM:
cycleIDs = randomRank(ids, cycleNum);
break;
default:
cycleIDs = loopRank(ids, cycleNum);
break;
} return cycleIDs;
} /**
* 数组环形轮循
*
* @author wulinfeng
* @param ids
* @param num
* @return
*/
public static String[] loopRank(String[] ids, int num)
{
if ((null == ids) || (0 == ids.length))
{
return ids;
} // 如果轮转个数大于数组长度,则设置为1
if (num >= ids.length)
{
num = 1;
} int length = ids.length;
String[] temp = new String[length]; // 根据轮转个数进行轮转
System.arraycopy(ids, length - num, temp, 0, num);
System.arraycopy(ids, 0, temp, num, length - num); return temp;
} /**
* 随机轮循
*
* @author wulinfeng
* @param bookIDs
* @param num
* @return
*/
public static String[] randomRank(String[] ids, int num)
{
if (null == ids || 0 == ids.length)
{
return null;
} // 如果轮转个数大于数组长度,则设置为数组长度
if (num >= ids.length)
{
num = ids.length;
} List<String> list = new ArrayList<String>(Arrays.asList(ids));
List<String> reList = new ArrayList<String>(ids.length); int index;
java.util.Random r = new java.util.Random();
for (int i = 0; i < num; i++)
{
index = r.nextInt(list.size());
String s = list.remove(index);
reList.add(s);
} // 把其他元素保存到新数组中
reList.addAll(list); String[] newIds = new String[reList.size()];
return (String[])reList.toArray(newIds);
}
}
利用OsCache实现后端轮循的更多相关文章
- Let's Encrypt与DNS轮循
本文由网络安全研究员.securityheaders.io和report-uri.io创始人Scott Helme发布在其个人博客中.描述了如何使用Let's Encrypt的同时兼容DNS轮循. 早 ...
- 利用bootstrap写图片轮播
利用bootstrap写图片轮播 缺点是轮播没有固定样式图片样式会改变外框的大小,所以要再设置 以及左右按钮的style也要从新设置 <div class="carousel slid ...
- ajax轮循
使用 AJAX 进行异步加载轮询操作.简单代码如下: <script> // 执行ajax轮循操作 function polling(){ var xmlhttp; // 判断浏览器--创 ...
- ajax 轮循
使用 AJAX 进行异步加载轮询操作.简单代码如下: <script> // 执行ajax轮循操作 function polling(){ var xmlhttp; // 判断浏览器--创 ...
- 线程轮循打印ABC...
package com.java.concurrent; import java.util.concurrent.locks.Condition; import java.util.concurren ...
- Linux日志轮循实现(shell)
在Linux系统中,日志的使用非常频繁,那么对日志就需要一定策略的管理,包括存放目录的设计,log文件命名规则,历史log文件的存放,log目录的容量限制,另外还有日志轮循. 日志轮循就是,将过期的l ...
- 【处理多服务器日志合并处理问题】多服务器的日志合并统计——apache日志的cronolog轮循
转发:http://www.chedong.com/tech/rotate_merge_log.html 内容摘要:你完全不必耐心地看完下面的所有内容,因为结论无非以下2点:1 用 cronolo ...
- 利用RecyclerView实现无限轮播广告条
代码地址如下:http://www.demodashi.com/demo/14771.html 前言: 公司产品需要新增悬浮广告条的功能,要求是可以循环滚动,并且点击相应的浮条会跳转到相应的界面,在实 ...
- Logrotate日志轮巡missingok: 在日志轮循期间,任何错误将被忽略
Linux日志文件总管——logrotate 编译自:http://xmodulo.com/2014/09/logrotate-manage-log-files-linux.html ...
随机推荐
- UVA-10054 The Necklace (欧拉回路)
题目大意:有n个珠子,珠子两边的颜色已知,问能否连成一条项链.(两个珠子可以项链当且仅当一个珠子的一边颜色与另一个珠子的另一边颜色相同). 题目分析:欧拉回路.将颜色视作节点,珠子当做边,问题变成了找 ...
- HDU 4696 Answers (脑补+数形结合)
题意 给一个图,每个点的出度为1,每个点的权值为1或者2.给Q个询问,问是否能找到一条路径的权值和M. 思路 由于每个点的出度为1,所以必然存在环.又因为c[i]只能取1或者2,可以组成任意值,所以只 ...
- 验证email是否合法
https://buluo.qq.com/p/detail.html?bid=339910&pid=6675390-1514450689&from=grp_sub_obj 场景1:验证 ...
- MongoHelper.cs
using System; using MongoDB.Bson; using MongoDB; using System.Web; using MongoDB.Driver; namespace Y ...
- C++复习12.程序内存管理
程序内存管理 20131006 一个程序在运行期间的内存是如何的对编写程序至关重要,之前整理的C++内存管理的知识和Java程序内存管理的知识.今天我们系统的整理一下程序的内存. 1.一个程序的内存有 ...
- node 封装db层
var db = {}; var mysql = require('mysql'); var pool = mysql.createPool({ connectionLimit: , host: '1 ...
- Alpha冲刺一 (2/10)
前言 队名:拖鞋旅游队 组长博客:https://www.cnblogs.com/Sulumer/p/9960487.html 作业博客:https://edu.cnblogs.com/campus/ ...
- 【剑指offer】n个骰子的点数,C++实现
# 题目 # 思路 # 代码
- CentOS 7.4搭建Kubernetes 1.8.5集群
环境介绍 角色 操作系统 IP 主机名 Docker版本 master,node CentOS 7.4 192.168.0.210 node210 17.11.0-ce node CentOS 7.4 ...
- threejs 画二维圆(圆弧)
画圆: var radius = 40, segments = 64, material = new THREE.LineBasicMaterial({ color: 0x0000ff }), geo ...