性格影响婚姻

小说:性格影响婚姻作者:陵华石更新时间:2019-05-19字数:10570

“好小子!”黄昏晓心中恨道:“原来你是引着本座说那句话呢?好让你堂而皇之、顺其自然的说出本座放你血的事!真是可恨!如今本座放了血,姜秀清这老鬼却是跟本座没完没了了,刚才本座还给他说只是刚把你弄来,根本没有做出什么伤害你的事儿!”

【情感问答】怎样和防备心强的女孩交往

纪太虚听了这话,头上竟然冒出了冷汗,心想到:“要是让我看你一个晚上的文章,侯爷我定要被你折磨疯了!现在还是三十六计——走为上策!”连忙说道:“不不,小子还有事儿,先走了!”说完,纪太虚竟然一跳跑了出去!
这种感知能力,是使自己的全身都是处在一种感知中,然后通过这种感知力来确定对方的方位,并且做出相应的反应。

这些被埋在土里的川军兄弟们满头满脸全是泥灰,只露出来两只眼睛,鼻孔耳朵里都是泥土,好在及时将他们给捞出来,否则估计就给闷死在泥土里了。

代码地址:https://github.com/vikde/demo-guava-cache

一、简介

guava cache是google guava中的一个内存缓存模块,用于将数据缓存到JVM内存中.实际项目开发中经常将一些比较公共或者常用的数据缓存起来方便快速访问.

内存缓存最常见的就是基于HashMap实现的缓存,为了解决并发问题也可能也会用到ConcurrentHashMap等并发集合,但是内存缓存需要考虑很多问题,包括并发问题、缓存过期机制、缓存移除机制、缓存命中统计率等.

guava cache已经考虑到这些问题,可以上手即用.通过CacheBuilder创建缓存、然后设置缓存的相关参数、设置缓存的加载方法等.本例子主要讲解guava cache的基本用法,详细的说明已在代码中说明.

 

二、代码示例

 1 package com.vikde.demo.guava.cache;
 2 
 3 import com.google.common.cache.CacheBuilder;
 4 import com.google.common.cache.CacheLoader;
 5 import com.google.common.cache.LoadingCache;
 6 
 7 import java.text.SimpleDateFormat;
 8 import java.util.Date;
 9 import java.util.Random;
10 import java.util.concurrent.TimeUnit;
11 
12 /**
13  * google guava cache 缓存demo
14  *
15  * @author vikde
16  * @date 2017/12/14
17  */
18 public class DemoGuavaCache {
19     public static void main(String[] args) throws Exception {
20         LoadingCache<Integer, String> cache = CacheBuilder.newBuilder()
21                                                           //设置并发级别为8,并发级别是指可以同时写缓存的线程数
22                                                           .concurrencyLevel(8)
23                                                           //设置缓存容器的初始容量为10
24                                                           .initialCapacity(10)
25                                                           //设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
26                                                           .maximumSize(100)
27                                                           //是否需要统计缓存情况,该操作消耗一定的性能,生产环境应该去除
28                                                           .recordStats()
29                                                           //设置写缓存后n秒钟过期
30                                                           .expireAfterWrite(17, TimeUnit.SECONDS)
31                                                           //设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite
32                                                           //.expireAfterAccess(17, TimeUnit.SECONDS)
33                                                           //只阻塞当前数据加载线程,其他线程返回旧值
34                                                           //.refreshAfterWrite(13, TimeUnit.SECONDS)
35                                                           //设置缓存的移除通知
36                                                           .removalListener(notification -> {
37                                                               System.out.println(notification.getKey() + " " + notification.getValue() + " 被移除,原因:" + notification.getCause());
38                                                           })
39                                                           //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
40                                                           .build(new DemoCacheLoader());
41 
42         //模拟线程并发
43         new Thread(() -> {
44             //非线程安全的时间格式化工具
45             SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
46             try {
47                 for (int i = 0; i < 15; i++) {
48                     String value = cache.get(1);
49                     System.out.println(Thread.currentThread().getName() + " " + simpleDateFormat.format(new Date()) + " " + value);
50                     TimeUnit.SECONDS.sleep(3);
51                 }
52             } catch (Exception ignored) {
53             }
54         }).start();
55 
56         new Thread(() -> {
57             SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
58             try {
59                 for (int i = 0; i < 10; i++) {
60                     String value = cache.get(1);
61                     System.out.println(Thread.currentThread().getName() + " " + simpleDateFormat.format(new Date()) + " " + value);
62                     TimeUnit.SECONDS.sleep(5);
63                 }
64             } catch (Exception ignored) {
65             }
66         }).start();
67         //缓存状态查看
68         System.out.println(cache.stats().toString());
69     }
70 
71     /**
72      * 随机缓存加载,实际使用时应实现业务的缓存加载逻辑,例如从数据库获取数据
73      */
74     public static class DemoCacheLoader extends CacheLoader<Integer, String> {
75         @Override
76         public String load(Integer key) throws Exception {
77             System.out.println(Thread.currentThread().getName() + " 加载数据开始");
78             TimeUnit.SECONDS.sleep(8);
79             Random random = new Random();
80             System.out.println(Thread.currentThread().getName() + " 加载数据结束");
81             return "value:" + random.nextInt(10000);
82         }
83     }
84 }

 

三、策略分析

expireAfterWrite 写缓存后多久过期
expireAfterAccess 读写缓存后多久过期
refreshAfterWrite 写入数据后多久过期,只阻塞当前数据加载线程,其他线程返回旧值

这几个策略时间可以单独设置,也可以组合配置

expireAfterWrite与refreshAfterWrite单独使用与混合使用的策略分析

已知配置条件:
Thread-1 每 3 秒获取一次缓存id=1的数据
Thread-2 每 5 秒获取一次缓存id=1的数据
加载一次缓存加载数据耗时 8 秒

1、expireAfterWrite单独使用

expireAfterWrite=17

Thread-2 加载数据开始
Thread-2 加载数据结束
Thread-1 01:04:07 value:6798
Thread-2 01:04:07 value:6798
Thread-1 01:04:10 value:6798
Thread-2 01:04:12 value:6798
Thread-1 01:04:13 value:6798
Thread-1 01:04:16 value:6798
Thread-2 01:04:17 value:6798
Thread-1 01:04:19 value:6798
Thread-1 01:04:22 value:6798
Thread-2 01:04:22 value:6798
1 value:6798 被移除,原因:EXPIRED
Thread-1 加载数据开始
Thread-1 加载数据结束
Thread-1 01:04:33 value:7836
Thread-2 01:04:33 value:7836
Thread-1 01:04:36 value:7836
Thread-2 01:04:38 value:7836
Thread-1 01:04:39 value:7836

说明:

启动时Thread-2加载数据,此时缓存中无数据,Thread-1阻塞等待Thread-2加载完成数据. 在设置的时间数据过期后Thread-1加载数据,Thread-2本应该01:04:22后的5秒加载数据,但是Thread-1等待3秒后加载,数据加载耗时8秒,所以Thread-2在01:04:33时加载数据成功.

结论:

当其他线程在加载数据的时候,当前线程会一直阻塞等待其他线程加载数据完成.

2、refreshAfterWrite单独使用

refreshAfterWrite=17

Thread-2 加载数据开始
Thread-2 加载数据结束
Thread-1 01:13:32 value:551
Thread-2 01:13:32 value:551
Thread-1 01:13:35 value:551
Thread-2 01:13:37 value:551
Thread-1 01:13:38 value:551
Thread-1 01:13:41 value:551
Thread-2 01:13:42 value:551
Thread-1 01:13:44 value:551
Thread-1 01:13:47 value:551
Thread-2 01:13:47 value:551
Thread-1 加载数据开始
Thread-2 01:13:52 value:551
Thread-2 01:13:57 value:551
Thread-1 加载数据结束
1 value:551 被移除,原因:REPLACED
Thread-1 01:13:58 value:827
Thread-1 01:14:01 value:827
Thread-2 01:14:02 value:827
Thread-1 01:14:04 value:827
Thread-2 01:14:07 value:827

说明:

启动时Thread-2加载数据,此时缓存中无数据,Thread-1阻塞等待Thread-2加载完成数据. 在设置的时间数据过期后Thread-1加载数据,Thread-2仍然按照策略获取到旧数据成功.

结论:

当没有数据的时候,其他线程在加载数据的时候,当前线程会一直阻塞等待其他线程加载数据完成;如果有数据的情况下其他线程正在加载数据,当前线程返回旧数据.

3、expireAfterWrite与refreshAfterWrite一起使用情况一

expireAfterWrite=13

refreshAfterWrite=17

Thread-2 加载数据开始
Thread-2 加载数据结束
Thread-1 01:18:32 value:5901
Thread-2 01:18:32 value:5901
Thread-1 01:18:35 value:5901
Thread-2 01:18:37 value:5901
Thread-1 01:18:38 value:5901
Thread-1 01:18:41 value:5901
Thread-2 01:18:42 value:5901
Thread-1 01:18:44 value:5901
1 value:5901 被移除,原因:EXPIRED
Thread-1 加载数据开始
Thread-1 加载数据结束
Thread-2 01:18:55 value:1300
Thread-1 01:18:55 value:1300
Thread-1 01:18:58 value:1300
Thread-2 01:19:00 value:1300
Thread-1 01:19:01 value:1300

说明:

启动时Thread-2加载数据,此时缓存中无数据,Thread-1阻塞等待Thread-2加载完成数据. 在设置的时间数据过期后Thread-1加载数据,Thread-2本应该01:18:42后的5秒加载数据,但是Thread-1等待3秒后加载,数据加载耗时8秒,所以Thread-2在01:18:55时加载数据成功.

结论:

当其他线程在加载数据的时候,当前线程会一直阻塞等待其他线程加载数据完成,与单独使用expireAfterWrite一样的效果.

4、expireAfterWrite与refreshAfterWrite一起使用情况二

expireAfterWrite=17

refreshAfterWrite=13

Thread-2 加载数据开始
Thread-2 加载数据结束
Thread-1 01:20:25 value:1595
Thread-2 01:20:25 value:1595
Thread-1 01:20:28 value:1595
Thread-2 01:20:30 value:1595
Thread-1 01:20:31 value:1595
Thread-1 01:20:34 value:1595
Thread-2 01:20:35 value:1595
Thread-1 01:20:37 value:1595
Thread-2 加载数据开始
Thread-1 01:20:40 value:1595
Thread-2 加载数据结束
Thread-1 01:20:48 value:2277
1 value:1595 被移除,原因:EXPIRED
Thread-2 01:20:48 value:2277
Thread-1 01:20:51 value:2277
Thread-2 01:20:53 value:2277
Thread-1 01:20:54 value:2277
Thread-1 01:20:57 value:2277
Thread-2 01:20:58 value:2277
Thread-1 01:21:00 value:2277
Thread-1 加载数据开始
Thread-2 01:21:03 value:2277
Thread-1 加载数据结束
Thread-2 01:21:11 value:3750
1 value:2277 被移除,原因:EXPIRED
Thread-1 01:21:11 value:3750
Thread-1 01:21:14 value:3750
Thread-2 01:21:16 value:3750
Thread-1 01:21:17 value:3750
Thread-1 01:21:20 value:3750
Thread-2 01:21:21 value:3750

说明:

启动时Thread-2加载数据,此时缓存中无数据,Thread-1阻塞等待Thread-2加载完成数据. 在设置的时间数据过期后Thread-2加载数据,Thread-1仍然按照策略在01:20:40获取到旧数据成功,但是本应该01:20:45继续获取一次数据但是等到01:20:48才获取成功.

结论:

当没有数据的时候,其他线程在加载数据的时候,当前线程会一直阻塞等待其他线程加载数据完成; 如果有数据的情况下其他线程正在加载数据,已经超过refreshAfterWrite设置时间但是没有超过expireAfterWrite设置的时间时当前线程返回旧数据. 如果有数据的情况下其他线程正在加载数据,已经超过expireAfterWrite设置的时间时当前线程阻塞等待其他线程加载数据完成. 这种情况适合与设置一个加载缓冲区的情况,既能保证过期后加载数据,又能保证长时间没访问多个线程并发时获取到过期旧数据的情况.

编辑:王秉秉

发布:2019-05-19 01:16:14

当前文章:http://adsl66.com/ask/question_16977.html

好运气是自己创造出来的 来不及,你就不学了吗? 宝宝半夜耳痛为哪般 永远不要考验人性 罗李华:金牛座2016年运势 妈妈要重视,宝宝打呼噜,不是睡得香! 处世哲学名言 这类碧池碰不得

34810 32719 76700 76231 26788 53190 17936 17663 74433 56276 88588 34914 95768 76487 19039 86034 36168 78299 73074 90892

我要说两句: (0人参与)

发布