(二)多线程与并发之synchronized和Lock

一 Java对象内存与Synchronized

(1)对象组成

(2)对象头组成

(3)锁升级

 

(4)synchronized使用场景

(5)synchronized底层原理

①同步代码块

同步代码块使用的是monitorenter和monitorexit指令,进入代码块时,执行monitor enter指令,就会获取当前对象的所有权,获取成功计数器+1,重入则把计数器+1,执行完后执行monitor exit,计数器-1,直到计数器为0,才可以被其他线程持有。

②同步方法

当执行方法的时候,先判断是否是同步方法,然后ACC_SYNCHRONIZED会隐式的调用monitorenter和monitorexit指令。

(6)jdk1.6后对synchronized的优化

偏向锁:当锁对象第一次被线程获取时,虚拟机会把对象头的标志位设置为01,偏向模式设置为1,表示进入偏向模式,同时使用CAS把获取到锁的线程ID记录在对象头的Mark Word中。如果CAS成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作。

轻量级锁:代码进入同步块时,对象无锁,虚拟机将在线程的栈帧建立一个Lock Record,用于存储对象Mark Word的拷贝,然后把Lock Record中的owner指向对象,虚拟机将通过CAS把对象的Mark Word更新为指向Lock Record的指针。CAS更新成功则加锁成功修改标志位00,否则意味着存在竞争,虚拟机判断Mark word是否指向栈帧,如果是则表示线程已经拥有了对象锁,否则继续锁升级,修改锁的标志位10,后面的线程阻塞。 解锁时,通过CAS把对象当前的Mark Word与栈帧中的Lock Record替换回来,如果成功,同步过程顺利完成,否则表示其他线程尝试过获取该锁,就要在释放锁的同步唤醒挂起的线程。

自旋锁和自适应自旋锁:Java线程与操作系统线程一一对应,当线程获取锁失败后,会由用户态切换到内核态挂起,线程被唤醒后,再有内核态切换到用户态,在一定程度影响并发性能。自旋锁是使用cpu时间换线程阻塞与调度开销,当线程获取锁失败后,不会马上阻塞自己,而是多次尝试获取锁资源,当达到获取次数上限才会被阻塞。自适应意味着线程自旋次数不再固定,如果在同一个锁对象上,自旋刚刚成功获取了锁,那么虚拟机会认为本次自旋也能成功获取锁,进而允许自旋更多次数。

锁消除:对于一些代码要求同步,但是被检测到不可能存在共享数据的竞争,因此可以消除锁。

锁粗化:如果一系列的连续操作都对同一个对象反复加锁解锁,则将把加锁同步的范围扩展到整个操作序列的外部。

二 Lock

(1)AQS概述

AQS里面维护了一个FIFO的双向队列和状态信息state。state=0表示锁空闲,当state=1表示锁被占有。

(2)ReentrantLock

ReentrantLock底层是使用AQS实现的可重入独占锁。state=0表示当前锁空闲,state>1表示锁已被占用。

(3)ReentrantReadWriteLock

ReentrantReadWriteLock使用state高16位表示获取到读锁的个数,低16位表示写锁的可重入次数,通过CAS操作实现读写分离。写锁是独占可重入锁,写锁是共享可重入锁。

三 synchronized与Lock区别

①synchronized是JVM层面的,Lock是JDK层面的。

②synchronized会自动释放锁,Lock需要手动释放锁。

③synchronized不可中断的,Lock可中断可不中断。

④Lock可以知道线程有没有拿到锁,synchronized不可以。

⑤synchronized可锁方法和代码块,Lock只能锁代码块。

⑥Lock可以使用读锁提高多线程读效率。

⑦synchronized是非公平锁,ReentrantLock可以设置是否为公平锁。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值