基础之重蹈覆辙

MESI缓存一致性协议

前🌽:

高速缓存底层数据结构:拉链散列表的结构

   bucket  - cache entry -  tag主内存地址 cache line缓存数据 flag缓存行状态

     cache line64字节  有效引用主内存地址,连续的相邻的数据结构 读取特别快

  处理器读写高速缓存,据变量名执行内存地址解码的操作,解析出:

     index 定位到拉链散列表中的某个bucket

     tag定位 cache entry

     offerset定位变量在 cache line位置

每核CPU有自己的L1 L2缓存,多线程编程 另一核想访问当前核内L1 L2数据?

   mesi缓存不命中且数据块在另一个缓存时,容许缓存到缓存的数据复制:高效

状态转换

初始:没有加载任何数据,I

本地写local write:本地处理器写数据到I的缓存行,M

本地读local read:本地处理器读I状态缓存行,此缓存没有数据可读

    其他处理器缓存里没有此行数据,从内存加载数据到缓存行 设成E,只有me有

    其他处理器有,此缓存行S(M状态的缓存行 由本地处理器写入/读出 状态不改)

远程读:c1 c2,c2需要c1缓存行数据,c1通过内存控制器memory controller发送c2,内存从总线存该份数据,c2将相应缓存行=S

远程写:c2得到c1数据,c2发RFO(request for owner) 拥有该份数据的权限,其他处理器相应缓存行=I 无权再操作该份数据,性能消耗大,什么情况下出现FRO,修改共享数据的时候

   两个线程修改同一个cache line中不同的数据,轮番发送RFO占用缓存行拥有权,切换I  ,而且其他线程读取此行数据L1 L2都是失效的,L3最新但是读取耗性能 更别说跨槽读 only内存上加载

  涉及到一个伪共享问题,解决:让不同线程操作对象处于不同缓存行--》缓存行填充

     缓存行64字节,java对象头markwork固定8字节(32)/12字节(64压缩不压16),填充6个无用长整形6*8字节,不同对象不同缓存行

对象头与锁状态

对象头:hotspot 

   markWord:存储hashCode,分代年龄 锁标志位 ,非固定结构 存储尽量多数据,动态调整,对象的状态复用自己存储空间,随着锁标志位的变化而变化

   Klass point元数据指针,通过指针确定对象是哪个类的实例

  

无锁:25bit存对象头hashcode,4bit存放对象分代年龄,1bit是否偏向锁的标识位 2bit锁标识位01

偏向锁:25bit空间中 23bit存放线程id 2bit存放epoch 4bit分代年龄 1bit是否偏向锁标识 0无锁 1偏向锁 锁标识位01

轻量级锁:30bit指向栈中锁记录的指针   2bit锁标识位:00

重量级锁:30bit指向重量级锁的指针,2bit存放锁标识位:11

GC标记:开辟30bit内存空间没有用上,2bit存放锁标志位11

内存分配:

  age_bits:分代回收的标识,4字节

  lock_bits:锁标志位,2字节

  biased_lock_bits:是否偏向锁标识,1字节

  max_hash_bits:无锁计算的hashcode占用字节数量,32位虚拟机 32-4-2-1= 25,64位64-4-2-1=57,25字节不用,hashcode占用31位

  hash_bits:64位虚拟机,最大字节>31,取31 否则真实字节数

  cms_bits:不是64位虚拟机占0byte,否则1byte

  epoch_bits:epoch所占有字节大小,2字节

monitor:

   线程私有的数据结构,每个线程都有一个可用monitor record列表  全局可用列表;每个被锁住的对象都会和一个monitor关联,monitor有owner字段存放拥有锁的线程的唯一标识

   synchronized通过对象内部监视器锁monitor实现,本质依赖底层操作系统mutex lock互斥锁实现,操作系统实现线程间切换需要用户态转换到核心态,成本高,状态转换时间长:重量级锁

 -XX:-UseBiasedLocking=false来禁用偏向锁

锁分类

   无锁:循环内进行修改,不断尝试修改共享资源, 只有一个能修改成功 其他循环重试

   偏向锁:第一次synchronized,修改对象头锁标志位:偏向锁,执行完同步代码块后 第二次达到同步代码块 线程会判断持有锁是不是自己,是 则正常执行 

     线程访问同步代码块,markwork获取线程id  CAS判断

     撤销:等待全局安全点,没有字节码执行,暂停拥有偏向锁的线程,判断对象是否被锁定,对象头无锁状态01或00轻量级锁  撤销偏向锁

轻量级锁:关闭偏向锁/多个线程竞争偏向锁导致锁升级 

  锁竞争:线程尝试获取锁,该锁被占有,自旋 等待释放,cas修改对象头锁标志位 

  长时间自旋非常耗费资源,其他线程原地空耗cpu 执行不了有效任务:忙等

重量级锁:忙等有限度(计数器记录自旋次数10),锁竞争严重达到最大自旋次数的线程,轻量级转重量级CAS修改锁标志位不改线程id,后续线程发现是重量级锁 将自己挂起 等待唤醒

控制权交给操作系统,操作系统负责线程间调度和线程状态变更

并发基础++-CSDN博客

锁的五种状态

JVM:

cpu使用过高:方法导致 

磁盘IO高:栈

内存过高:堆

GC:堆

YGC:eden区满了  

动态分配规则:

    相同age的对象的大小之和 > 1/2的存活区大小 sum(age.mem)>=1/2S0, >=age的对象挪动到老年代

redis缓存三大问题:

缓存穿透:不存在的数据,布隆过滤器或者黑白名单 缓存预热

缓存击穿热点数据失效,互斥锁/分布式锁  预热失效时快速刷新缓存

    互斥锁/分布式锁: 

   永不过期:redis不设置过期时间,后台异步线程刷新缓存

       存过期时间,快过期去更新

缓存雪崩:大量数据同时失效,随机过期时间 限流 预热 自动刷新

    多级缓存 / 缓存预热 / 限流

数据一致性问题

不重要业务:先更数据库再删缓存(暂时性不一致)

    缓存更新成功返回,异步线程去更新数据库(缓存挂了,数据丢失)

双写:先写myql在写redis,事务

数据同步:定期mysql同步到redis,定时任务 变更数据时触发同步

实时数据流:实时数据流 消息队列 ,mysql变更同步到redis 

设计模式

工厂模式:

创建对象的接口,具体的对象创建延迟到子类

单例模式:

饿汉式:类加载时初始化,线程安全

懒汉式:用到的时候实例对象并赋值属性 返回

反射:强制访问

序列化破坏单例:序列化写入磁盘 使用时从磁盘读取对象反序列化

  反序列化对象重新分配内存,readResolve解决了被破坏的问题

枚举单例模式:无序列号问题 不能被反射获取

百度安全验证

daj

学会这10种定时任务,我有点飘了_crond

这个有人知道吗?什么位图定时任务?

:的ack

  ack=0 不等待确认 

 ack=1 leader确认入盘,默认

 ack=all,等待isr所有的副本确认

消息丢失:

生产者producer:默认send异步发送,改成get同步发送,等待被broker成功接收再发下一条

   或者注册回调函数:重试直到成功

   重试机制:网络/broker故障,尝试重试 设置acks

    性能:客户端使用buffer累积一定数量才发送

    ISR:与leader保持同步到副本列表,被isr列表副本成功接收才消息被成功存 储

broker:数据持久化到磁盘

   默认写入pageCache后向producer响应

  改为同步刷盘 flush.messages写*条fsync,flush.ms*毫秒fsync刷盘

副本机制:分区配副本

消费者consumer:关闭自动提交offset,消费逻辑幂等性

   默认:自动提交 开始poll先看是否auth.commit.interval.ms满足先提上一批消息的位移再处理下一批消息:重复消费

  enable.auto.commit=false手动提交,消费完准备提 宕机了 重启再次消费:至少消费一次

  spring-kafka@KafkaListener enable.auth.commit=false  ackmode=manual手动提交

Kafka的消息可靠性(防止消息丢失)_flush.messages kafka-CSDN博客

百度安全验证

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值