范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

重新认识下JVM级别的本地缓存框架GuavaCache优秀从何而来

  大家好,又见面了。
  本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面。如果感兴趣,欢迎关注以获取后续更新。
  不知不觉,这已经是《深入理解缓存原理与实战设计》系列专栏的第6篇文章了。经过前面5篇文章的铺垫,我们系统且全面地介绍了缓存相关的概念与典型问题,也手动实操了如何构建一个本地最简版本的通用缓存框架,还对JAVA主流的本地缓存规范进行了解读。
  秉持着不重复造轮子的理念,本篇文章中,我们就来一起深入剖析JAVA本地缓存的优秀"  轮子  " —— 来自 Google 家族的 Guava Cache  。聊一聊其实现机制 、看一看如何使用 。
  Guava Cache初识
  Guava  是Google提供的一套JAVA的工具包,而 Guava Cache  则是该工具包中提供的一套完善的JVM级别 的高并发缓存框架。其实现机制类似ConcurrentHashMap,但是进行了众多的封装与能力扩展。作为JVM级别的本地缓存框架,Guava Cache  具备缓存框架该有的众多基础特性。当然,Guava Cache能从众多本地缓存类产品中脱颖而出,除了具备上述基础缓存特性外,还有众多贴心的能力增强,绝对算得上是工具包届的超级暖男 !为什么这么说呢?我们一起看下Guava Cache的能力介绍,应该可以有所体会。
  支持缓存记录的过期设定
  作为一个合格的缓存容器,支持缓存记录过期是一个基础能力。  Guava Cache  不但支持设定过期时间,还支持选择是根据插入时间  进行过期处理(创建过期 )、或者是根据最后访问时间  进行过期处理(访问过期 )。
  过期策略
  具体说明
  创建过期
  基于缓存记录的插入时间判断。比如设定10分钟过期,则记录加入缓存之后,  不管有没有访问  ,10分钟时间到则
  访问过期
  基于最后一次的访问时间来判断是否过期。比如设定10分钟过期,如果缓存记录被访问到,则以最后一次访问时间重新计时;只有连续10分钟没有被访问的时候才会过期,否则将一直存在缓存中不会被过期。
  实际使用的时候,可以在创建缓存容器的时候指定过期策略即可:  基于  创建时间  过期 public Cache createUserCache() {     return CacheBuilder.newBuilder()         .expireAfterWrite(30L, TimeUnit.MINUTES)         .build(); } 基于  访问时间  过期 public Cache createUserCache() {     return CacheBuilder.newBuilder()         .expireAfterAccess(30L, TimeUnit.MINUTES)         .build(); }
  是不是很方便?
  支持缓存容量限制与不同淘汰策略
  作为内存型缓存,必须要防止出现内存溢出的风险。Guava Cache支持设定缓存容器的最大存储上限,并支持根据缓存记录  条数  或者基于每条缓存记录的权重  (后面会具体介绍)进行判断是否达到容量阈值。
  当容量触达阈值后,支持根据  FIFO + LRU  策略实施具体淘汰处理以腾出位置给新的记录使用。
  淘汰策略
  具体说明
  FIFO
  根据缓存记录写入的顺序,先写入的先淘汰
  LRU
  根据访问顺序,淘汰最久没有访问的记录
  实际使用的时候,同样是在创建缓存容器的时候指定容量上限与淘汰策略,这样就可以放心大胆地使用而不用担心内存溢出问题咯。  限制缓存  记录条数  public Cache createUserCache() {     return CacheBuilder.newBuilder()             .maximumSize(10000L)             .build(); } 限制缓存  记录权重  public Cache createUserCache() {     return CacheBuilder.newBuilder()             .maximumWeight(10000L)             .weigher((key, value) -> (int) Math.ceil(instrumentation.getObjectSize(value) / 1024L))             .build();     }
  这里需要注意:按照权重进行限制缓存容量的时候必须要指定  weighter  属性才可以生效。上面代码中我们通过计算value  对象的字节数(byte)来计算其权重信息,每1kb的字节数作为1个权重,整个缓存容器的总权重限制为1w,这样就可以实现将缓存内存占用控制在10000*1k 10M  左右。
  有没有很省心?
  支持集成数据源能力
  在前面文章中,我们有介绍过缓存的  三种模型  ,分别是 旁路型  、穿透型  、异步型  。Guava Cache作为一个封装好的缓存框架,是一个典型的穿透型缓存 。正常业务使用缓存时通常会使用旁路型缓存,即先去缓存中尝试查询获取数据,如果获取不到则会从数据库中进行查询并加入到缓存中;而为了简化业务端使用复杂度,Guava Cache支持集成数据源,业务层面调用接口查询缓存数据的时候,如果缓存数据不存在,则会自动去数据源中进行数据获取并加入缓存中。public User findUser(Cache cache, String userId) {     try {         return cache.get(userId, () -> {             System.out.println(userId + "用户缓存不存在,尝试回源查找并回填...");             return userDao.getUser(userId);         });     } catch (ExecutionException e) {         e.printStackTrace();     }     return null; }
  实际使用的时候如果查询的用户不存在,则会自动去回源查找并写入缓存里,再次获取的时候便可以从缓存直接获取:
  上面的方法里,是通过在get方法里传入  Callable  实现的方式指定回源获取数据的方式,来实现缓存不存在情况的自动数据拉取与回填到缓存中的。实际使用的时候,除了Callable方式,还有一种CacheLoader  的模式,也可以实现这一效果。
  需要我们在创建缓存容器的时候声明容器为  LoadingCache  类型(下面的章节中有介绍),并且指定 CacheLoader  处理逻辑:public LoadingCache createUserCache() {     return CacheBuilder.newBuilder()             .build(new CacheLoader() {                 @Override                 public User load(String key) throws Exception {                     System.out.println(key + "用户缓存不存在,尝试CacheLoader回源查找并回填...");                     return userDao.getUser(key);                 }             });     }
  这样,获取不到数据的时候,也会自动回源查询并填充。比如我们执行如下调用逻辑:      public static void main(String[] args) {         CacheService cacheService = new CacheService();         LoadingCache cache = cacheService.createUserCache();         try {             System.out.println(cache.get("123"));             System.out.println(cache.get("124"));             System.out.println(cache.get("123"));         } catch (Exception e) {             e.printStackTrace();         }     }
  执行结果如下:  123用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=123, userName=铁柱, department=研发部) 124用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=124, userName=翠花, department=测试部) User(userId=123, userName=铁柱, department=研发部)
  两种方式都可以实现这一效果,实际可以根据需要与场景选择合适的方式。
  当然,有些时候,可能也会涉及到  CacheLoader  与Callable  两种方式结合使用的场景,这种情况下优先 会执行Callable提供的逻辑,Callable缺失的场景会使用CacheLoader提供的逻辑。public static void main(String[] args) {     CacheService cacheService = new CacheService();     LoadingCache cache = cacheService.createUserCache();     try {         System.out.println(cache.get("123", () -> new User("xxx")));         System.out.println(cache.get("124"));         System.out.println(cache.get("123"));     } catch (Exception e) {         e.printStackTrace();     } }
  执行后,可以看出Callable逻辑被  优先执行  ,而CacheLoader作为  兜底策略  存在:  User(userId=xxx, userName=null, department=null) 124用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=124, userName=翠花, department=测试部) User(userId=xxx, userName=null, department=null)
  支持更新锁定能力
  这个是与上面数据源集成一起的辅助增强能力。在高并发场景下,如果某个key值没有命中缓存,大量的请求同步打到下游模块处理的时候,很容易造成  缓存击穿  问题。
  为了防止缓存击穿问题,可以通过  加锁  的方式来规避。当缓存不可用时,仅 持锁的线程  负责从数据库中查询数据并写入缓存中,其余请求重试时先尝试从缓存中获取数据,避免所有的并发请求全部同时打到数据库上。
  作为穿透型缓存的保护策略之一,  Guava Cache  自带了  并发锁定  机制,同一时刻仅允许一个请求去回源获取数据并回填到缓存中,而其余请求则阻塞等待,不会造成数据源的压力过大。
  有没有被暖心到?
  提供了缓存相关的一些监控统计
  引入缓存的一个初衷是希望缓存能够提升系统的处理性能,而有限缓存容量中仅存储部分数据的时候,我们会希望存储的有限数据可以尽可能的覆盖并抗住大部分的请求流量,所以对缓存的  命中率  会非常关注。
  Guava Cache深知这一点,所以提供了  stat  统计日志,支持查看缓存数据的加载或者命中情况统计。我们可以基于命中情况,不断地去优化代码中缓存的数据策略,以发挥出缓存的最大价值。
  Guava Cache的统计信息封装为  CacheStats  对象进行承载,主要包含一下几个关键指标项:
  指标
  含义说明
  hitCount
  命中缓存次数
  missCount
  没有命中缓存次数(查询的时候内存中没有)
  loadSuccessCount
  回源加载的时候加载成功次数
  loadExceptionCount
  回源加载但是加载失败的次数
  totalLoadTime
  回源加载操作总耗时
  evictionCount
  删除记录的次数
  缓存容器创建的时候,可以通过  recordStats()  开启缓存行为的统计记录:    public static void main(String[] args) {         LoadingCache cache = CacheBuilder.newBuilder()                 .recordStats()                 .build(new CacheLoader() {                     @Override                     public User load(String key) throws Exception {                         System.out.println(key + "用户缓存不存在,尝试CacheLoader回源查找并回填...");                         User user = userDao.getUser(key);                         if (user == null) {                             System.out.println(key + "用户不存在");                         }                         return user;                     }                 });          try {             System.out.println(cache.get("123");             System.out.println(cache.get("124"));             System.out.println(cache.get("123"));             System.out.println(cache.get("126"));          } catch (Exception e) {         } finally {             CacheStats stats = cache.stats();             System.out.println(stats);         }     }
  上述代码执行之后结果输出如下:  123用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=123, userName=铁柱, department=研发部) 124用户缓存不存在,尝试CacheLoader回源查找并回填... User(userId=124, userName=翠花, department=测试部) User(userId=123, userName=铁柱, department=研发部) 126用户缓存不存在,尝试CacheLoader回源查找并回填... 126用户不存在 CacheStats{hitCount=1, missCount=3, loadSuccessCount=2, loadExceptionCount=1, totalLoadTime=1972799, evictionCount=0}
  可以看出,一共执行了4次请求,其中1次命中,3次回源处理,2次回源加载成功,1次回源没找到数据,与打印出来的  CacheStats  统计结果完全吻合。
  有着上述能力的加持,前面将Guava Cache称作"  暖男  "不过分吧?
  Guava Cache适用场景
  在本系列专栏的第一篇文章《聊一聊作为高并发系统基石之一的缓存,会用很简单,用好才是技术活》中,我们在缓存的一步步演进介绍中提过本地缓存与集中式缓存的区别,也聊了各自的优缺点。
  作为一款纯粹的本地缓存框架,Guava Cache具备本地缓存该有的  优势  ,也无可避免的存在着本地缓存的 弊端  。
  维度
  简要概述
  优势
  基于  空间换时间  的策略,利用内存的高速处理效率,提升机器的处理性能,减少大量对外的 IO请求 交互,比如读取DB、请求外部网络、读取本地磁盘数据等等操作。
  弊端
  整体  容量受限  ,可能对本机内存造成压力。此外,对于分布式多节点集群部署的场景,缓存更新场景会出现 缓存漂移  问题,导致各个节点之间的缓存 数据不一致 。
  鉴于上述优劣综合判断,可以大致圈定  Guava Cache  的实际适用场合:数据  读多写少  且对 一致性要求不高  的场景
  这类场景中,会将数据缓存到本地内存中,采用定时触发(或者事件推送)的策略重新加载到内存中。这样业务处理逻辑直接从内存读取需要的数据,修改系统配置项之后,需要等待一定的时间后方可生效。
  很多的配置中心采用的都是这个缓存策略。统一配置中心中管理配置数据,然后各个业务节点会从统一配置中心拉取配置并存储在自己本地的内存中然后使用本地内存中的数据。这样可以有效规避配置中心的单点故障问题,降低了配置中心的请求压力,也提升了业务节点自身的业务处理性能(减少了与配置中心之间的网络交互请求)。  对  性能  要求 极其严苛  的场景
  对于分布式系统而言,集中式缓存是一个常规场景中很好的选项。但是对于一些超大并发量且读性能要求严苛的系统而言,一个请求流程中需要频繁的去与Redis交互,其网络开销也是不可忍受的。所以可以采用将数据本机内存缓存的方式,分散redis的压力,降低对外请求交互的次数,提升接口响应速度。  简单的本地数据缓存,作为  HashMap/ConcurrentHashMap  的替代品
  这种场景也很常见,我们在项目中经常会遇到一些数据的需要临时缓存一下,为了方便很多时候直接使用的  HashMap  或者ConcurrentHashMap  来实现。而Guava Cache聚焦缓存场景做了很多额外的功能增强(比如数据过期能力支持、容量上限约束等),可以完美替换掉HashMap/ConcurrentHashMap,更适合缓存场景使用。
  Guava Cache使用引入依赖
  使用Guava Cache,首先需要引入对应的依赖包。对于Maven项目,可以在  pom.xml  中添加对应的依赖声明即可:     com.google.guava     guava     31.1-jre 
  这样,就完成了依赖引入。
  容器创建 —— CacheBuilder
  具体使用前首先面临的就是如何创建Guava Cache实例。可以借助  CacheBuilder  以一种优雅的方式来构建出合乎我们诉求的Cache实例。
  对  CacheBuilder  中常见的属性方法,归纳说明如下:
  方法
  含义说明
  newBuilder
  构造出一个Builder实例类
  initialCapacity
  待创建的缓存容器的初始容量大小(记录  条数  )
  maximumSize
  指定此缓存容器的最大容量(最大缓存记录  条数  )
  maximumWeight
  指定此缓存容器的最大容量(最大  比重  值),需结合 weighter  方可体现出效果
  expireAfterWrite
  设定过期策略,按照数据  写入时间  进行计算
  expireAfterAccess
  设定过期策略,按照数据最后  访问时间  来计算
  weighter
  入参为一个函数式接口,用于指定每条存入的缓存数据的权重占比情况。这个需要与  maximumWeight  结合使用
  refreshAfterWrite
  缓存写入到缓存之后
  concurrencyLevel
  用于控制缓存的并发处理能力,同时支持多少个线程  并发写入  操作
  recordStats
  设定开启此容器的数据加载与缓存命中情况统计
  基于  CacheBuilder  及其提供的各种方法,我们可以轻松的进行缓存容器的构建、并指定容器的各种约束条件。
  比如下面这样:  public LoadingCache createUserCache() {     return CacheBuilder.newBuilder()             .initialCapacity(1000) // 初始容量             .maximumSize(10000L)   // 设定最大容量             .expireAfterWrite(30L, TimeUnit.MINUTES) // 设定写入过期时间             .concurrencyLevel(8)  // 设置最大并发写操作线程数             .refreshAfterWrite(1L, TimeUnit.MINUTES) // 设定自动刷新数据时间             .recordStats() // 开启缓存执行情况统计             .build(new CacheLoader() {                 @Override                 public User load(String key) throws Exception {                     return userDao.getUser(key);                 }             }); }
  业务层使用
  Guava Cache容器对象创建完成后,可以基于其提供的对外接口完成相关缓存的具体操作。首先可以了解下Cache提供的对外操作接口:
  对关键接口的含义梳理归纳如下:
  接口名称
  具体说明
  get
  查询指定key对应的value值,如果缓存中没匹配,则基于给定的  Callable  逻辑去获取数据回填缓存中并返回
  getIfPresent
  如果缓存中存在指定的key值,则返回对应的value值,否则返回null(此方法  不会触发  自动回源与回填操作)
  getAllPresent
  针对传入的key列表,返回缓存中存在的对应value值列表(  不会触发  自动回源与回填操作)
  put
  往缓存中添加key-value键值对
  putAll
  批量往缓存中添加key-value键值对
  invalidate
  从缓存中删除指定的记录
  invalidateAll
  从缓存中批量删除指定记录,如果无参数,则清空所有缓存
  size
  获取缓存容器中的总记录数
  stats
  获取缓存容器当前的统计数据
  asMap
  将缓存中的数据转换为  ConcurrentHashMap  格式返回
  cleanUp
  清理所有的已过期的数据
  在项目中,可以基于上述接口,实现各种缓存操作功能。  public static void main(String[] args) {     CacheService cacheService = new CacheService();     LoadingCache cache = cacheService.createUserCache6();     cache.put("122", new User("122"));     cache.put("122", new User("122"));     System.out.println("put操作后查询:" + cache.getIfPresent("122"));     cache.invalidate("122");     System.out.println("invalidate操作后查询:" + cache.getIfPresent("122"));     System.out.println(cache.stats()); }
  执行后,结果如下:  put操作后查询:User(userId=122, userName=null, department=null) invalidate操作后查询:null CacheStats{hitCount=1, missCount=1, loadSuccessCount=0, loadExceptionCount=0, totalLoadTime=0, evictionCount=0}
  当然,上述示例代码中这种使用方式有个明显的弊端就是业务层面对Guava Cache的  私有API  依赖过深 ,后续如果需要替换Cache组件的时候会比较痛苦,需要对业务调用的地方进行大改。所以真正项目里面,最好还是对其适当封装,以实现业务层面的解耦 。如果你的项目是使用Spring框架,也可以基于Spring Cache  统一规范来集成并使用Guava Cache,降低对业务逻辑的侵入 。
  小结回顾
  好啦,关于Guava Cache的功能与关键特性介绍,以及项目中具体的集成与使用方法,就介绍到这里了。总结一下,Guava Cache其实就是一个增强版的大号ConcurrentHashMap,在保证线程安全的情况下,增加了缓存必备的数据过期、容量限制、回源策略等能力,既保证了本身的精简,又使得整体能力足以满足大部分本地缓存场景的使用诉求。也正是由于这些原因,Guava Cache在JAVA领域广受好评,使用范围非常的广泛。
  下一篇文章中,我们将继续对Guava Cache展开讨论,跳出使用层面,剖析其内部核心实现逻辑。如果有兴趣,欢迎关注后续文章的更新。
  那么,关于本文中提及的内容,你是否有自己的一些想法与见解呢?欢迎评论区一起交流下,期待和各位小伙伴们一起切磋、共同成长。
  补充说明1   : 本文属于《深入理解缓存原理与实战设计》系列专栏的内容之一。该专栏围绕缓存这个宏大命题进行展开阐述,全方位、系统性地深度剖析各种缓存实现策略与原理、以及缓存的各种用法、各种问题应对策略,并一起探讨下缓存设计的哲学。
  如果有兴趣,也欢迎关注此专栏。
  补充说明2   : 关于本文中涉及的  演示代码  的完整示例,我已经整理并提交到github中,如果您有需要,可以自取:https://github.com/veezean/JavaBasicSkills
  我是悟道,聊技术、又不仅仅聊技术~
  如果觉得有用,请  点赞 + 关注  让我感受到您的支持。也可以关注下我的公众号【架构悟道】,获取更及时的更新。
  期待与你一起探讨,一起成长为更好的自己。

大结局丨切尔西曼联利物浦巴黎压哨签!巴萨成功免签阿隆索官方切尔西宣布和布罗亚签下了一份2028年到期的6年合同。本赛季20岁的布罗亚已经代表图赫尔的球队替补出战了3场比赛,这名前锋在上赛季租借效力于南安普顿时表现非常出色,他在38场各11!马内还是不如莱万!拜仁跌至第三,德甲终于有了悬念北京时间9月3日2130,德甲第5轮迎来一场焦点大战卫冕冠军拜仁慕尼黑客战劲敌柏林联合。前4轮战罢,拜仁柏林联合均为3胜1平积10分,拜仁以净胜球优势位列德甲积分榜榜首。本轮先结束呼吁建立人民币稳定币,工程院士为中国web3。0支招9月2日,在今日百度举行的2022WAIC元宇宙分论坛上,中国工程院院士张平表示,建设以数字人民币为锚定基础的链上支付系统,是实现我国政治安全经济安全文化安全以及网络空间安全的核心林志颖救命恩人收到的感谢礼物曝光!仅有21箱饮料及24杯奶茶近日,林志颖车祸后发文报平安,透露几天前已经出院,正在慢慢恢复期待回归舞台。到了8月31日,林志颖又公开首张照片,曝光体重仅53。7公斤,比车祸前轻了10公斤,经纪人称因为长期躺在长期用香薰的人后果是这样?太可怕了现代人工作太忙碌,压力太大。工作和生活的时候,点一支香,既可以舒缓身心,提神醒气,养生健体。也让我们在匆忙之间,感受到一丝从容和惬意,更好的去应对工作的挑战感受生活的乐趣。现代人越游戏买量观我为什么忧虑三七互娱的未来?头条创作挑战赛2022年8月31日,游戏买量龙头三七互娱公布了半年报。财报显示,2022年上半年三七互娱的整体营收为80。92亿元,同比增长7。34归属于上市公司股东的净利润16。街机游戏忍者棒球,游戏按键毁灭者有没有熟悉这个画面的小伙伴,我有一个朋友(注意是我的朋友),他人生第一个水泡在手指上,便是玩游戏按出来的。忍者棒球是一款经典街机游戏,游戏中可以选四名忍者棒球手,故事内容很简单,棒王者荣耀排位上分攻略之一实力运气和队友大家好,今天,我们来讲王者荣耀上分攻略。因为上分技巧太多太多,今天我们先说说最重要的几点,那就是实力运气和队友。首先,王者以上变数太多,能到达王者的玩家其实也不需要看太多攻略,各有四款高性价比真香神机,游戏拍照十分全面,价格最低仅1599元您在阅读前请点击上面的关注二字,后续会第一时间为您提供更多有价值的相关内容,感谢您的支持。虽然每年各大品牌都发布上百款手机,但是并非所有的手机型号都值得购买,有一些经典的机型,性价望子成龙!詹皇晒与两个儿子暴扣对比照三个国王9月4日消息,湖人当家球星勒布朗詹姆斯最大梦想之一,就是和自己的儿子同场竞技,如今两个儿子布朗尼和布莱斯都被父亲赋予了更高的期望。詹姆斯和妻子萨瓦娜一共有三个孩子,大儿子布朗尼17两个太阳下的生存之道寻找外星生命的新目标有个后羿射日的神话故事,说的是天上原先有10个太阳,是东方天帝的10个儿子,后来被一个叫后羿的神箭手射死9个,现在天上只剩下1个太阳。这个神话想象力丰富,但也反
1万多中国人居住在津巴布韦,100多家中资企业,在津中国人现状目前统计有1万左右的中国人居住在津巴布韦,主要居住在哈拉雷布拉瓦约奎鲁奎奎等城市。有100多家中资企业,中资企业员工大约有6000人左右。在津巴布韦规模比较大的中国企业目前有30多一人公司股东在何种情况下需要对公司债务承担连带责任?作者丨童元玲原标题一人公司股东连带责任研究童元玲北京市长安律师事务所律师曾经的一人股东公司,将股权转让给另外两个股东,变为非一人公司后,原来的一人股东是否需要对公司债务承担连带责任加速撤离!新兴市场债券资金流出创纪录,低利率新兴经济体却受宠受到发达经济体大幅收紧货币政策和乌克兰局势的影响,投资者今年正大举撤离新兴市场债券,同期流出规模创17年之最。不过,并非所有新兴市场债券都遭到抛售,与此前先发制人加息利率较高的新兴四家村镇银行存款即将垫付!为什么分三步走而不是一次性全部垫付历时八十多天,河南村镇银行线上存款无法支取事件终于取得突破性进展,7月11日河南银保监局河南省地方金融监管局联合发布(第1号)公告,即万众瞩目的处置方案。公告内容称,对于涉及的禹州25岁的李天一已经出狱?82岁老父亲李双江,再为他找工作?继我爸是李刚之后,又一个坑爸儿子诞生了。当时李双江已经72岁了,是中国著名的歌手。谁也不会想到,他会以这种方式在网络上走红。而李天一也因为这件事被劳教,一年后被放回家。然而李双江刚油头粉面就不要再尬演军人了!这8位男星演军人,看着让人太难受文蜀人未晰2006年,王宝强许三多一角走红,而士兵突击也被评为最接近真实军旅生活的电视剧。剧中的段奕宏陈思成用实力演绎出了军人的刚毅和柔情。多年后,两个叫不出名字的小鲜肉,在综艺节给父亲买了一款智能手机,性价比还不错爸爸一直到现在还使用多年前几百款的智能手机,于是我想网上给父亲买一款智能手机,要求性能好,不卡顿,流畅,于是我看上了这款ipone7。这款手机是采用了A10Fusion处理器,比A光做电影不够?漫威对决将多元宇宙融入游戏剧情,灭霸是最弱BOSS光做电影不够?漫威对决将多元宇宙融入游戏剧情,灭霸是最弱BOSS?对于漫威电影,相信每个人都看过那么几部,不过最近几年,由于种种原因,漫威的电影很难再在国内上映了,距离上一次漫威的二孩催生无果,生育警报拉响?专家提出新建议,父母们表示赞同统计局数据显示,我国2020年的出生率只有0。85,到2021年继续下降仅0。75,人口出生率跌破1。数据显示,2021年,我国人口净增长48万,新生儿数量仅为1062万人。7月1再见郭艾伦!再见赵继伟!男篮亚洲杯主力名单敲定,杜锋留了一手北京时间7月12日,男篮亚洲杯小组赛正式打响,中国男篮方面也公布了最终的球员大名单。值得关注的是,最新一版的亚洲杯男篮球员名单,照此前征战世预赛时的人员分布还是有很大变化的。首先是爆大冷!国乒劲敌连遭重击日本奥运主力出局,韩国名将一轮游北京时间2022年7月12日,WTT球星挑战赛布达佩斯站结束资格赛首日争夺,男单资格赛和女单资格赛都爆出了大冷门。男单赛场,日本奥运主力选手丹羽孝希2比3出局,让人大跌眼镜。另外,