com.holmos.cache.element.Element Maven / Gradle / Ivy
package com.holmos.cache.element;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import com.holmos.cache.element.listener.ElementAccessListener;
import com.holmos.cache.size.layout.sizegetter.ReflectSizeGetter;
import com.holmos.cache.size.layout.sizegetter.SizeGetter;
import com.holmos.cache.size.layout.sizegetter.SizeGetterFactory;
/**
* 缓存的元素类型,包含key,value和此元素的属性信息
*
* @author: 吴银龙([email protected])
* @version: 2013-3-7 下午12:48:29
*/
public class Element implements Serializable,Cloneable,ElementAccessListener{
private static final long serialVersionUID = -1032104732342127102L;
private static ReflectSizeGetter sizeGetter;
static{
ArrayList getters=new ArrayList();
getters.add(SizeGetterFactory.ARRAY_SIZE_GETTER);
getters.add(SizeGetterFactory.OBJECT_SIZE_GETTER);
sizeGetter = new ReflectSizeGetter(getters);
}
/**hitCount字段的原子更新器,因为hitCount是要被并发增加的,但只要保证最终正确就行*/
private static final AtomicLongFieldUpdater HITCOUNT_UPDATER = AtomicLongFieldUpdater.newUpdater(Element.class, "hitCount");
/**缓存元素访问监听器列表*/
private ArrayList elementAccessListeners;
/** the key */
private Object key;
/**the value */
private Object value;
/**采用乐观锁来控制读写的并发,version为当前元素的版本号*/
private volatile long version;
/**缓存元素在缓存中的命中率,get的时候,如果该元素在缓存中,则get一次此值+1*/
private volatile long hitCount;
/**此元素的现有可生存时间,一旦为0,则为失效元素(ms) */
private volatile int timeToLive = Integer.MIN_VALUE;
/**此元素剩余的闲置时间,如果时间一旦为0,则此为失效元素(ms) */
private volatile int timeToIdle = Integer.MIN_VALUE;
/**此元素的创建时间(ms),在replace操作的时候此时间也会发生更新*/
private volatile long creationTime;
/**元素的最近一次访问时间(ms)*/
private volatile long lastAccessTime;
/**元素发生更新操作的时候,put操作和replace操作,此属性更新为操作完成时间*/
private volatile long lastUpdateTime;
/**元素占用存储空间大小*/
private int size;
/**此值为真,那么不能进行写操作*/
private volatile boolean writeLocked;
/**此值为真,那么不能进行读操作*/
private volatile boolean readLocked;
/**
* 以对象的形式返回value的值
*
* 这个是用受JVM管理的内存的getValue的方法,不进行序列化处理,直接返回原生的缓存对象
*
* @return 缓存元素对象
* */
public Object getValue(){
return value;
}
/**
* 以对象形式返回索引key
*
* 这个是用受JVM管理的内存的getKey的方法,不进行序列化处理,直接返回原生的缓存对象
*
* @return 缓存元素的key属性
* */
public Object getKey(){
return key;
}
/**
* 获取缓存元素占用内存大小,JVM内部缓存的占用空间大小,而非序列化之后的大小
*
* @return 缓存元素占用空间大小
* */
public int getSize(){
if(0 == size)
size=sizeGetter.getDataSize(value);
return size;
}
/**
* 判断该缓存元素是否和value是同一个缓存元素,判断的方法很简单,只要他们的key一致就判定他们是同一个元素,因为同一个缓存里面不可能存在两个key一致的情况
*
* 如果value == null 则返回false
* 如果value 不是{@link Element}类型,则返回false
* 如果元素自己和value的key有一个为null为错误情况,直接返回false
* 如果元素自己的key和value的key不一致,返回false
*
* @return true 两个缓存元素相同
false 两个缓存元素不同
* */
@Override
public boolean equals(Object value){
if( null== value ||!(value instanceof Element))
return false;
Element element = (Element)value;
if(null == key || element.getKey() == null)
return false;
if( key.equals(element.getKey()))
return true;
return false;
}
/**
* 获取缓存元素的创建时间点(ms)
*
* the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
*
* @return 缓存元素的创建时间点(ms)
* */
public long getCreationTime(){
return creationTime;
}
/**
* 设置缓存元素的生存时间(单位:ms)
*
* 0代表生存时间无限大
*
* @param timeToLiveMilliseconds
* */
public void setTimeToLive(int timeToLiveMilliseconds){
if(timeToLiveMilliseconds < 0 )
throw new IllegalArgumentException("缓存元素的生存时间不能设置为负数!");
timeToLive = timeToLiveMilliseconds;
}
/**
* 获得缓存元素的最大生存时间
*
* @return 缓存元素的最大生存时间
* */
public int getTimeToLive(){
return timeToLive;
}
/**
* 设置缓存元素的最大空闲时间,即元素在最后一次访问或者创建到元素过期之间的最大时间(单位:ms)
*
* 0代表永不过期
*
* @param timeToIdleMilliseconds
* */
public void setTimeToIdle(int timeToIdleMilliseconds){
if(timeToIdleMilliseconds < 0)
throw new IllegalArgumentException("缓存元素的空闲时间不能设置为负数!");
timeToIdle = timeToIdleMilliseconds;
}
/**
* 获得缓存元素的最大空闲时间
*
* @return 缓存元素的最大空闲时间
* */
public int getTimeToIdle(){
return timeToIdle;
}
/**
* 设置该缓存元素的版本号,由于该操作很频繁,在开发的时候注意版本号不能是负数,也尽量不要小于之前的版本号
*
* @param version 待设置的版本号
* */
public void setVersion(long version){
this.version=version;
}
/**
* 获取该元素当前的版本号
*
* @return 该元素当前的版本号
* */
public long getVersion(){
return version;
}
/**
* 获取最近的更新时间,如果还没有发生更新,则返回创建时间
*
* @return 最近的更新时间
* */
public long getLastUpdateTime(){
if( 0 == lastUpdateTime )
return creationTime;
return lastUpdateTime;
}
/**
* 获取最近的访问时间,读取和更新的时候都会更新最近访问时间
*
* @return 最近的访问时间
* */
public long getLastAccessTime(){
return lastAccessTime;
}
/**
* 获取该缓存数据的命中次数
*
* @return 缓存数据的命中次数
* */
public long getHitCount(){
return hitCount;
}
/**
* 重置访问状态:置hitCount = 0,lastAccessTime = 当前时间,发生在put操作之后
*
*
* */
public void resetAccessStatistics(){
HITCOUNT_UPDATER.set(this, 0);
lastAccessTime = System.currentTimeMillis();
lastUpdateTime = lastAccessTime;
}
/**
* 更新访问状态:hitCount++,lastAccessTime = 当前时间,发生在get操作之后
*
* */
public void updateAccessStatistics(){
HITCOUNT_UPDATER.incrementAndGet(this);
lastAccessTime = System.currentTimeMillis();
}
/**
* 一旦元素的值发生改变,将会更新元素的 更新信息
*
* 发生在update之后
* */
public void updateModifyStatistics(){
updateAccessStatistics();
lastUpdateTime = System.currentTimeMillis();
}
/**
* 获得缓存元素的描述信息
*
* @return 元素的描述信息
* */
@Override
public String toString(){
StringBuilder elementDescribe = new StringBuilder();
elementDescribe.append("[ key = ").append(key)
.append(", value=").append(value)
.append(", version=").append(version)
.append(", hitCount=").append(hitCount)
.append(", CreationTime = ").append(this.getCreationTime())
.append(", LastAccessTime = ").append(this.getLastAccessTime())
.append(" ]");
return elementDescribe.toString();
}
/**
* 查看缓存元素是否过期
*
* 首先校验缓存元素是否超过了生存时间,也就是说看看now-creationtime &rt timeToLive
* 在没有超过生存时间的时候,看缓存元素的空闲时间是否过了空闲期限
*
* @return true 缓存元素已过期
false 缓存元素未过期
* */
public boolean isExpired(){
long expireTime = getExpireTime();
return expireTime < System.currentTimeMillis();
}
/**
* 获取缓存元素的过期时间,从生存时间和空闲时间双方面去考虑
*
* @return 缓存元素的过期时间点
*/
private long getExpireTime() {
long liveExpireTime = creationTime+timeToLive;
long idleExpireTime = Math.max(lastAccessTime, creationTime)+timeToIdle;
return Math.min(liveExpireTime, idleExpireTime);
}
public boolean isWriteLocked() {
return writeLocked;
}
public boolean isReadLocked() {
return readLocked;
}
public synchronized boolean lockWrite(){
boolean oriWriteLock = this.writeLocked;
this.writeLocked = true;
return oriWriteLock;
}
public synchronized void releaseWrite(){
this.writeLocked = false;
}
public synchronized boolean lockRead(){
boolean oriReadLock = this.readLocked;
this.readLocked = true;
return oriReadLock;
}
public synchronized void releaseRread(){
this.readLocked = false;
}
public ArrayList getElementAccessListeners() {
return elementAccessListeners;
}
public void registerElementAccessListener(ElementAccessListener elementAccessListener) {
this.elementAccessListeners.add(elementAccessListener);
}
public void removeElementAccessListener(ElementAccessListener elementAccessListener){
this.elementAccessListeners.remove(elementAccessListener);
}
public void clearElementAccessListeners(){
this.elementAccessListeners.clear();
}
@Override
public void beforeGet() {
for(ElementAccessListener listener:elementAccessListeners){
listener.beforeGet();
}
}
@Override
public void afterGet() {
for(ElementAccessListener listener:elementAccessListeners){
listener.afterGet();
}
}
@Override
public void beforeInsert() {
for(ElementAccessListener listener:elementAccessListeners){
listener.beforeInsert();
}
}
@Override
public void afterInsert() {
for(ElementAccessListener listener:elementAccessListeners){
listener.afterInsert();
}
}
@Override
public void beforeUpdate() {
for(ElementAccessListener listener:elementAccessListeners){
listener.beforeUpdate();
}
}
@Override
public void afterUpdate() {
for(ElementAccessListener listener:elementAccessListeners){
listener.afterUpdate();
}
}
@Override
public void beforeDelete() {
for(ElementAccessListener listener:elementAccessListeners){
listener.beforeDelete();
}
}
@Override
public void afterDelete() {
for(ElementAccessListener listener:elementAccessListeners){
listener.afterDelete();
}
}
}