Java 面试题目的那些事。。。。。 CAS 机制。对象内存布局,Synchronized  的实现过程, volatile

1. CAS 介绍:

CAS 是Java 并发包的基础。 CAS 是 英文单词 compare and swap  ,即 比较和交换。什么意思呢? 举一个例子: 当一个线程要去尝试修改一个值 1 变为 0的过程,首先: 线程获取到这个值1 ,然后:将拿着 0 去替换1 的时候,再次比较之前获取的1 与原始值 是不是相等,如果相等则替换,更改为0;否则再次尝试操作之前的动作,知道成功为止。这就是 CAS的大体含义。 从中我们 可以发现这是一种自旋的过程,因此很消耗cup。 不过底层实现仍是 C++编写,通过 lock cmpxchg 指令实现。

2. CAS 存在的缺陷:

2.1 ABA问题。 例如上面的例子: 当我们 1和原始值 1相等的情况下 ,再次过程中有可能另外一个线程,将 原始值 1 改为 2,又将 2改为1 ,此时原始值1已经不是原来的1了,但是对于我们并无法感知到它已经发生了变化。这就是所谓的 CAS 问题。

解决方案就是采用版本号机制,每次修改了原始值,我们同时将版本号加1,这样我们就可以区分,这个原始值是不是被改动过。

2.2 循环时间长消耗大。  由于这个过程是自旋的操作,对 cpu 消耗极大。如果JVM能支持处理器提供的pause指令那么效率会有一定的提升

2.3  只能保证一个共享变量的原子操作。对于多个共享变量,CAS不能保证共享变量的原子性。我们可以采用 锁保证,还可以 ,从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作

 

3. jvm 对象的内存布局

3.1   在 HotSpot 虚拟机中,对象在内存中存储布局分为 3 块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。但是 header 又分为 markword 和 class pointer 两部分。

 

对象头--markword  存储 如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳、对象分代年龄,这部分信息称为“Mark Word”;Mark Word 被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据自己的状态复用自己的存储空间。

对象头-- class pointer  储存 是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;

实例数据  实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。

        对齐填充  不是必然存在的,没有特别的含义,它仅起到占位符的作用。

 

4. Synchronized  的实现过程:

      4.1 方法 和代码块中 synchronized,保证线程安全。 4.2 实际上synchronized 修饰的代码  在class 中由 minitorEnter 和 monitorExit 标记。  4.3 锁升级 :偏向锁 -> 轻量级锁 -> 重量级锁 的过程   4.4. 在 Cpu 指令由 lock cmpchag 实现。

 

5. volatile

 5.1   并发编程的3个概念: 可见性 ,有序性 ,原子性

5.2  可见性: 可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。  Java 中volatile 关键字 可见性。 当一个共享变量被 volatile 修饰时候,变量被修改,会及时的刷新到主内存,其他线程访问改变量会到主内存中去获取,这就保证了变量的可见性。

5.3 有序性: volatile 禁止进行指令从排序。加入volatile关键字时,会多出一个lock前缀指令

  lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:

  1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;

  2)它会强制将对缓存的修改操作立即写入主存;

  3)如果是写操作,会在写之后插入一个写屏障指令,他会强制将数据刷新到主内存,是各个cpu的高速缓存去的数据强制失效。

4) 如果是读操作,会在读之前插入一个 读屏障指令,他会强制缓存区的数据失效,从主缓存中获取。

 

5.4 原子性。volatile 不能保证操作的原子性。 对于可见性,只能保证获取值为主内存中最新值,不能保证操作的原子性。 对于 有序性, 虽然在写操作后能刷新数据到主内存,使高速缓存失效,在多线程情况下,如果这个写操作,中途出现阻塞,那么其他线程可能获取到主内存的数据,不是想要的结果。

 

 

 

 

  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值