9.3学习笔记(线程与锁复习及CAS、ConcurrentHashMap实现原理)

学习笔记
摘要由CSDN通过智能技术生成

目录

1.并发编程

1.1 volatile

2. 锁(预防死锁):  【重点】

2.1 锁的实现机制

2.2  锁的转换

2.3 锁的分类

公平锁/非公平锁

构造器

可重入锁

独享锁/共享锁

乐观锁/悲观锁

偏向锁/轻量级锁/重量级锁

自旋锁

自适宜自旋锁:

锁消除

synchronized和lock比较

同步集合和并发集合

并发集合的使用建议

3. ConcurrentHashMap实现原理

3.1 Segment分段锁

2.内部结构

4. CAS

4.1 CAS应用

4..2 CAS为什么能保证原子操作?


1.并发编程

 三种性质:
    - 可见性:一个线程对共享变量的修改,另一个线程能立刻看到。缓存可导致可见性问题
    - 原子性:一个或多个CPU执行操作不被中断。线程切换可导致原子性问题
    - 有序性:编译器优化可能导致指令顺序发生改变。编译器优化可能导致有序性问题。
         > 有序性问题指的是在多线程环境下多核,由于执行语句重排序后,重排序的这一部
         分没有一起执行完,就切换到了其它线程,导致的结果与预期不符的问题。这就是编
         译器的编译优化给并发编程带来的程序有序性问题       
  三个问题:
    - 安全性问题:线程安全
    - 活跃性问题:死锁、活锁、饥饿
    - 性能问题:
        - 使用无锁结构:TLS线程局部存储(ThreadLocal),Copy-On-Write,乐观锁;Java
        的原子类,Disruptor无锁队列
        - 减少锁的持有时间:让锁细粒度。如ConcurrentHashmap;再如读写锁,读无锁写有锁

1.1 volatile

 C语言中的原意:禁用CPU缓存,从内存中读出和写入。 
  Java语言的引申义:
    - Java会将变量立刻写入内存,其他线程读取时直接从内存读(普通变量改变后,什么时候写
    入内存是不一定的)
    - 禁止指令重排序
解决问题:
    - 保证可见性
    - 保证有序性
    - 不能保证原子性

2. 锁(预防死锁):  【重点】

     - 互斥:不能破坏
     - 占有且等待:同时申请所有资源
     - 不可抢占:sychronized解决不了,Lock可以解决
     - 循环等待:给资源设置id字段,每次都是按顺序申请锁

2.1 锁的实现机制

 Java对象存储在堆Heap内存。一个Java对象概括起来分为对象头、对象体和对齐字节JMM。 
    
        - 对象头中的Mark Word标记字主要用来表示对象的线程锁状态,另外还可以用来配合GC、存放该对象的hashCode。
      - Klass Word是一个指向方法区中Class信息的指针,意味着该对象可随时知道自己是哪个Class的实例。
       - 数组长度也是占用64位-8字节的空间,这是可选的,只有当本对象是一个数组对象时才会有这个部分。
       - 对象体是用于保存对象属性和值的主体部分,占用内存空间取决于对象的属性数量和类型。
       - 对齐字是为了减少堆内存的碎片空间,这是因为 JVM 虚拟机要求被管理的对象的大小都是8字节的整数倍。那么在某些情况下,就需要填充区域对不足的对象区域进行填充。

2.2  锁的转换

当对一个对象加锁其实是修改这个对象的markword信息,当new一个对象可能有两种状态,偏向锁已经启动和未启动  。普通new出一个对象加上synchronized,如果可偏向标识已经启动升级为偏向锁;如果偏向锁没有启动,直接到自旋锁,升级为轻量级锁,线程处于忙等状态。如果竞争进一步加剧则会升级为重量级锁。synchronized实现的同步锁,在JDK1.6之前叫做重量级锁。重量级锁会造成线程排队(串行执行),且会使CPU在用 户态和核心态之间频繁切换,所以代价高、效率低。

为了提高效率,不会一开始就使用重量级锁,JVM在内部会根据需要,按如下步骤进行锁的升级:【记住锁升级流程】
    - 初期锁对象刚创建时,还没有任何线程来竞争,对象的Mark Word是001,这偏向锁标识位是0,锁状态01,说明该对象处于无锁状态(无线程竞争它)
    - 当有一个线程来竞争锁时,先用偏向锁,表示锁对象偏爱这个线程,这个线程要执行这个锁关联的任何代码,不需要再做任何检查和切换,这种竞争不激烈的情况下,效率非常高。这时Mark Word会记录自己偏爱的线程的ID,把该线程当做自己的熟人。对象的mark word是101
    - 当有两个线程开始竞争这个锁对象,情况发生变化了,不再是偏向(独占)锁了,锁会升级为轻量级锁,两个线程公平竞争,哪个线程先占有锁对象并执行代码,锁对象的Mark Word就执行哪个线程的栈帧中的锁记录。对象的markword是00。
   - 如果竞争的这个锁对象的线程更多,导致了更多的切换和等待,JVM会把该锁对象的锁升级为重量级锁,这个就叫做同步锁,这个锁对象Mark Word再次发生变化,会指向一个监视器对象,这个监视器对象用集合的形式来登记和管理排队的线程。对象的mark word是10。

- synchronized修饰的代码块:通过反编译.class文件,通过查看字节码可以得到:在代码块中使用的是monitorenter和monitorexit指令,其中monitorenter指令指向同步代码块的开始位置,monitorexit指令指明同步代码块的结束位置需要注意monitorexit有2个,是因为退出同步代码块有2种情形,正常退出和异常退出
  - synchronized 修饰的方法:查看字节码可以得到:在同步方法中会包含A

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值