java缓存学习笔记

概述

缓存在计算机中是通过读取磁盘的数据放到内存中,然后进入cpu进行操作。这种机制可以在数据库查询等操作中,通过将一些热点数据放入缓存中,每次操作先判断该数据是否存在于缓存当中,减少对原始数据的访问,从而优化系统性能。

现在有的缓存形式一般分为本地缓存和分布式缓存。

在java单机缓存组件常见的有ehcache,guava cache,caffeine,在java spring5之后默认采用高性能的caffeine组件。

java ConcurrentHashMap缓存机制

java 中的锁

先补充一下多线程中锁的机制,借用其它文章来填充这一块多线程(4)什么是锁?锁机制,死锁等说明_简述线程锁和和死锁-CSDN博客

具体实现

在java7之前,CocurrentHashMap使用分段锁来实现线程安全,它通过将整个Hash表分成不同的段,进行操作时只需获得操作元素对应段的锁,虽然避免了全局锁,但是锁存在一定的争用。

在java8之后,CocurrentHashMap采用更细粒度的锁,每一个哈希桶都可以被独立的锁定,当多个线程访问不同桶时可以并行执行,相比分段锁有优化。

Compare-And-Swap操作

该操作有三个参数:地址,预期值,新值

其具体过程是先找到地址所指的值,并将该值与预期值对比,只有相同的时候将该地址的值修改为新值。

而这种操作在原始值与预期值不相同的时候,该操作不会执行,只可以重试。这就保证了多个线程同时修改一个地址的值的时候,最终结果也是一致的。

当然这种机制也有一定的缺点,在高竞争环境下可能会存在活锁的情况

Node->TreeNode

在数据量过大的时候,java8之后将java7的链表节点改为了红黑树节点,减少了时间复杂度,并且每个TreeNode都运用了CAS操作来保证线程安全。

Caffeine组件

这个贴文章了java - 性能利器Caffeine缓存全面指南 - 宋小黑 - SegmentFault 思否

redis在java中

在Java中操作Redis(详细-->从环境配置到代码实现)_自己实现redisjava-CSDN博客

(合着windows有redis啊)

缓存一致性

此部分借鉴b站上的一个视频,用redis举例(实现最终一致性)

视频来源,讲的还不错:

面试官:项目中怎样保证redis的缓存和数据库数据一致性?java高频面试八股文,建议收藏!_哔哩哔哩_bilibili

redis常用场景

(终于知道再看redis命令的时候过期时间是拿来干嘛的了)

而只是访问不修改的话是不会存在缓存一致性的问题的,而只有读跟写同时并发的时候才会出现缓存一致性的问题

而实际上就是修改的时候先动缓存还是先动数据库的问题

先修改缓存再更新数据库

这种方式面临着一个问题:对于缓存中的数据是删除还是修改。而一般更推荐删除,删除了之后下一次查询直接访问数据库(由于缓存中没有该数据)然后再将数据库中的数据放回缓存。推荐删除的原因是修改可能会有逻辑上的操作,就会增加复杂度,而删除就会好很多

问题所在

两个客户端分别同时发起了一个读和一个改的请求,改的请求先删除了reis中的数据,然后读的请求这时跟上发现缓存没有,而读更快先到达了原始的数据库,最后得到了数据返回给了缓存,这时修改的请求姗姗来迟到了数据库修改了数据,这个时候redis中的数据和数据库中的数据就不一样了。(当然还有其它情况)

解决方法

在那次修改请求之后再删除一次缓存,那么就只会出现一次的数据不一致。这一次的不一致是使用redis所带来的高效无法避免的一次不一致(没必要为了这一次不一致去上锁),实现最终一致性。

这种操作称为双删,第二次删除需要一定的延迟——保证如果有同时性的访问操作,在访问操作中将数据库中的数据放回redis之后进行双删中的第二次删除。

先操作数据库再操作缓存

问题所在

很明显,在操作数据库未操作缓存之前,如果有其它请求进来访问,就会直接访问redis缓存,然后出现不一致性。

当然保证了最终一致性,也就不需要解决了,理由同上。

杂项

这个视频里还讲解了删除失败的情况,一种mq的高耦合方法,另一种利用阿里开发的canal去监听日志,这个我就没去研究了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值