第二章 Java并发机制的底层实现原理

Java并发机制的底层实现原理

 

1、volatile的应用

volatile要保证共享变量的可见性。java规范中对volatile的定义如下:Java编程语言允许线程访问共享变量,为了确保共享变量能够被准确和一致地更新,线程应该用排他锁单独获得这个变量。计算机系统可以使用缓存一致性模型来保证volatile的可见性(例如MESI协议)。

值得注意的是volatile只保证可见性,而不保证原子性,例如i++操作是一个复合读写操作,其读是原子的,写是原子的,但复合读写就不一定是原子的。假定一个volatile变量i的初始值是0,线程一和和线程二都执行一个i++操作,执行结果可能为1。

 

2、synchronized的实现原理和应用

synchronized又称重量级锁。

利用synchronized实现同步的基础:每个对象都可以当作一个锁,具体表现为以下三种形式:

1、对于普通同步方法,锁是当前实例对象;

2、对于静态同步方法,锁是当前类的Class对象;

3、对于同步方法块,是synchronized后面配置的那个对象。

JVM基于进入和退出Monitor对象(monitorenter和monitorexit)的方法来实现方法同步和代码块同步。

 

synchronized用的锁是存储在对象头里的(Mark word中存储对象的hashcode和锁信息)。

 

Java SE 1.6为了减少锁的代价,引入了偏向锁和轻量级锁。所以锁一共有四种状态:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。

由于获取锁的往往是同一个进程,所以引入偏向锁。线程第一次访问同步块时,会在对象头和栈帧的锁记录里存储偏向锁的线程ID,以后该线程使用该锁时不需要进行CAS操作来加锁和解锁,只需检测对象头中存储的偏向锁线程ID与当前线程ID是否一致即可。偏向锁使用了一种只有竞争发生时才释放锁的机制,当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会交出偏向锁。

轻量级锁机制下,在进入同步区之前,先把对象头的Mark word字段复制到锁记录当中,然后线程会试图使用CAS将对象头的mark word修改为换为指向锁记录的指针,操作成功获得锁,失败则表示有其他线程竞争锁,当前线程将使用自旋的方式竞争锁。如果轻量级锁长时间得不到响应,将会膨胀为重量级锁并阻塞,迫使持有锁的线程交出锁并唤醒阻塞线程。

下面是三种锁的比较:

优点缺点适用场景
偏向锁加锁和解锁不需要额外的开销,和执行非同步方法仅有纳秒级的差距如果线程间存在锁竞争,会带来额外的撤销开销仅有一个线程访问同步块
轻量级锁竞争的线程不会阻塞,提高了程序的响应速度如果始终得不到锁竞争的线程,自旋会消耗CPU追求响应速率
重量级锁线程竞争不自旋,不损耗cpu线程阻塞,响应时间慢追求吞吐率


 

3、原子操作的实现原理

对于处理机而言,主要借助于总线锁和缓存锁两个机制来实现原子性。

在java中主要使用CAS和锁来实现原子性。事实上锁的底层使用了CAS操作,当一个线程想进入同步块时使用循环CAS的方式获取锁,退出同步区时用CAS操作释放锁。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值