gpt4 book ai didi

Java实现一个简单的缓存方法

转载 作者:qq735679552 更新时间:2022-09-27 22:32:09 26 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章Java实现一个简单的缓存方法由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

缓存是在web开发中经常用到的,将程序经常使用到或调用到的对象存在内存中,或者是耗时较长但又不具有实时性的查询数据放入内存中,在一定程度上可以提高性能和效率。下面我实现了一个简单的缓存,步骤如下.

创建缓存对象EntityCache.java 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class EntityCache {
   /**
    * 保存的数据
    */
   private Object datas;
 
   /**
    * 设置数据失效时间,为0表示永不失效
    */
   private long timeOut;
 
   /**
    * 最后刷新时间
    */
   private long lastRefeshTime;
 
   public EntityCache(Object datas, long timeOut, long lastRefeshTime) {
     this .datas = datas;
     this .timeOut = timeOut;
     this .lastRefeshTime = lastRefeshTime;
   }
   public Object getDatas() {
     return datas;
   }
   public void setDatas(Object datas) {
     this .datas = datas;
   }
   public long getTimeOut() {
     return timeOut;
   }
   public void setTimeOut( long timeOut) {
     this .timeOut = timeOut;
   }
   public long getLastRefeshTime() {
     return lastRefeshTime;
   }
   public void setLastRefeshTime( long lastRefeshTime) {
     this .lastRefeshTime = lastRefeshTime;
   }
 
 
}

定义缓存操作接口,ICacheManager.java 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public interface ICacheManager {
   /**
    * 存入缓存
    * @param key
    * @param cache
    */
   void putCache(String key, EntityCache cache);
 
   /**
    * 存入缓存
    * @param key
    * @param cache
    */
   void putCache(String key, Object datas, long timeOut);
 
   /**
    * 获取对应缓存
    * @param key
    * @return
    */
   EntityCache getCacheByKey(String key);
 
   /**
    * 获取对应缓存
    * @param key
    * @return
    */
   Object getCacheDataByKey(String key);
 
   /**
    * 获取所有缓存
    * @param key
    * @return
    */
   Map<String, EntityCache> getCacheAll();
 
   /**
    * 判断是否在缓存中
    * @param key
    * @return
    */
   boolean isContains(String key);
 
   /**
    * 清除所有缓存
    */
   void clearAll();
 
   /**
    * 清除对应缓存
    * @param key
    */
   void clearByKey(String key);
 
   /**
    * 缓存是否超时失效
    * @param key
    * @return
    */
   boolean isTimeOut(String key);
 
   /**
    * 获取所有key
    * @return
    */
   Set<String> getAllKeys();
}

实现接口ICacheManager,CacheManagerImpl.java 。

这里我使用了ConcurrentHashMap来保存缓存,本来以为这样就是线程安全的,其实不然,在后面的测试中会发现它并不是线程安全的.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
public class CacheManagerImpl implements ICacheManager {
   private static Map<String, EntityCache> caches = new ConcurrentHashMap<String, EntityCache>();
 
   /**
    * 存入缓存
    * @param key
    * @param cache
    */
   public void putCache(String key, EntityCache cache) {
     caches.put(key, cache);
   }
 
   /**
    * 存入缓存
    * @param key
    * @param cache
    */
   public void putCache(String key, Object datas, long timeOut) {
     timeOut = timeOut > 0 ? timeOut : 0L;
     putCache(key, new EntityCache(datas, timeOut, System.currentTimeMillis()));
   }
 
   /**
    * 获取对应缓存
    * @param key
    * @return
    */
   public EntityCache getCacheByKey(String key) {
     if ( this .isContains(key)) {
       return caches.get(key);
     }
     return null ;
   }
 
   /**
    * 获取对应缓存
    * @param key
    * @return
    */
   public Object getCacheDataByKey(String key) {
     if ( this .isContains(key)) {
       return caches.get(key).getDatas();
     }
     return null ;
   }
 
   /**
    * 获取所有缓存
    * @param key
    * @return
    */
   public Map<String, EntityCache> getCacheAll() {
     return caches;
   }
 
   /**
    * 判断是否在缓存中
    * @param key
    * @return
    */
   public boolean isContains(String key) {
     return caches.containsKey(key);
   }
 
   /**
    * 清除所有缓存
    */
   public void clearAll() {
     caches.clear();
   }
 
   /**
    * 清除对应缓存
    * @param key
    */
   public void clearByKey(String key) {
     if ( this .isContains(key)) {
       caches.remove(key);
     }
   }
 
   /**
    * 缓存是否超时失效
    * @param key
    * @return
    */
   public boolean isTimeOut(String key) {
     if (!caches.containsKey(key)) {
       return true ;
     }
     EntityCache cache = caches.get(key);
     long timeOut = cache.getTimeOut();
     long lastRefreshTime = cache.getLastRefeshTime();
     if (timeOut == 0 || System.currentTimeMillis() - lastRefreshTime >= timeOut) {
       return true ;
     }
     return false ;
   }
 
   /**
    * 获取所有key
    * @return
    */
   public Set<String> getAllKeys() {
     return caches.keySet();
   }
}

CacheListener.java,监听失效数据并移除.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class CacheListener{
   Logger logger = Logger.getLogger( "cacheLog" );
   private CacheManagerImpl cacheManagerImpl;
   public CacheListener(CacheManagerImpl cacheManagerImpl) {
     this .cacheManagerImpl = cacheManagerImpl;
   }
 
   public void startListen() {
     new Thread(){
       public void run() {
         while ( true ) {
           for (String key : cacheManagerImpl.getAllKeys()) {
             if (cacheManagerImpl.isTimeOut(key)) {
              cacheManagerImpl.clearByKey(key);
              logger.info(key + "缓存被清除" );
            }
           }
         }
       }
     }.start();
 
   }
}

测试类TestCache.java 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class TestCache {
   Logger logger = Logger.getLogger( "cacheLog" );
   /**
    * 测试缓存和缓存失效
    */
   @Test
   public void testCacheManager() {
     CacheManagerImpl cacheManagerImpl = new CacheManagerImpl();
     cacheManagerImpl.putCache( "test" , "test" , 10 * 1000L);
     cacheManagerImpl.putCache( "myTest" , "myTest" , 15 * 1000L);
     CacheListener cacheListener = new CacheListener(cacheManagerImpl);
     cacheListener.startListen();
     logger.info( "test:" + cacheManagerImpl.getCacheByKey( "test" ).getDatas());
     logger.info( "myTest:" + cacheManagerImpl.getCacheByKey( "myTest" ).getDatas());
     try {
       TimeUnit.SECONDS.sleep( 20 );
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
     logger.info( "test:" + cacheManagerImpl.getCacheByKey( "test" ));
     logger.info( "myTest:" + cacheManagerImpl.getCacheByKey( "myTest" ));
   }
 
   /**
    * 测试线程安全
    */
   @Test
   public void testThredSafe() {
     final String key = "thread" ;
     final CacheManagerImpl cacheManagerImpl = new CacheManagerImpl();
     ExecutorService exec = Executors.newCachedThreadPool();
     for ( int i = 0 ; i < 100 ; i++) {
       exec.execute( new Runnable() {
         public void run() {
             if (!cacheManagerImpl.isContains(key)) {
               cacheManagerImpl.putCache(key, 1 , 0 );
             } else {
               //因为+1和赋值操作不是原子性的,所以把它用synchronize块包起来
               synchronized (cacheManagerImpl) {
                 int value = (Integer) cacheManagerImpl.getCacheDataByKey(key) + 1 ;
                 cacheManagerImpl.putCache(key,value , 0 );
               }
             }
         }
       });
     }
     exec.shutdown();
     try {
       exec.awaitTermination( 1 , TimeUnit.DAYS);
     } catch (InterruptedException e1) {
       e1.printStackTrace();
     }
 
     logger.info(cacheManagerImpl.getCacheDataByKey(key).toString());
   }
}

testCacheManager()输出结果如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
2017-4-17 10:33:51 io.github.brightloong.cache.TestCache testCacheManager
信息: test:test
2017-4-17 10:33:51 io.github.brightloong.cache.TestCache testCacheManager
信息: myTest:myTest
2017-4-17 10:34:01 io.github.brightloong.cache.CacheListener$1 run
信息: test缓存被清除
2017-4-17 10:34:06 io.github.brightloong.cache.CacheListener$1 run
信息: myTest缓存被清除
2017-4-17 10:34:11 io.github.brightloong.cache.TestCache testCacheManager
信息: test:null
2017-4-17 10:34:11 io.github.brightloong.cache.TestCache testCacheManager
信息: myTest:null

testThredSafe()输出结果如下(选出了各种结果中的一个举例):

?
1
2
2017-4-17 10:35:36 io.github.brightloong.cache.TestCache testThredSafe
信息: 96

可以看到并不是预期的结果100,为什么呢?ConcurrentHashMap只能保证单次操作的原子性,但是当复合使用的时候,没办法保证复合操作的原子性,以下代码:

?
1
2
3
if (!cacheManagerImpl.isContains(key)) {
               cacheManagerImpl.putCache(key, 1 , 0 );
             }

多线程的时候回重复更新value,设置为1,所以出现结果不是预期的100。所以办法就是在CacheManagerImpl.java中都加上synchronized,但是这样一来相当于操作都是串行,使用ConcurrentHashMap也没有什么意义,不过只是简单的缓存还是可以的。或者对测试方法中的run里面加上synchronized块也行,都是大同小异。更高效的方法我暂时也想不出来,希望大家能多多指教.

原文链接:http://www.jianshu.com/p/bd8dc4a8bbc7# 。

最后此篇关于Java实现一个简单的缓存方法的文章就讲到这里了,如果你想了解更多关于Java实现一个简单的缓存方法的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com