synchronize和ReentrantLock

来源:互联网 发布:设计软件培训 编辑:程序博客网 时间:2024/05/21 06:26

分别介绍synchronized和ReentrantLock的实现原理

1,synchronized实现原理

synchronized是虚拟机的内置锁,经过编译之后,会在同步块的前后形成 monitorenter 和 monitorexit 两个字节码指令,每个对象都具有一个monitor与之关联,拥有了monitor的线程便锁住了对象,同时synchronized同步块对同一个线程是可重入的,进去一次monitor的count加1。java的线程是映射到操作系统的原生系统之上的,如果要阻塞或唤醒一个线程,都需要操作系统来帮忙完成,这就需要从用户态转换到核心态中,状态转换需要耗费很多的时间。所以synchronized属于一个重量级锁.之后虚拟机也进行了优化,比如:自旋锁,自适应自旋锁,轻量级锁,偏向锁。

自旋锁是线程没有获取到锁便进入忙循环,但又因为锁占用的时间长的话,自旋的时间太长浪费处理器资源,所以有了自适应自旋,自适应自旋的自旋的时间不再固定,而是根据前一次在同一个锁上的自旋时间决定的.如果对于某个锁自旋很少成功,则省掉自旋过程,避免浪费资源,如果刚刚获得过成功,则自旋等待的时间持续相对的更长.

轻量级锁是,在不存在锁竞争的时候起作用,当有锁竞争时会膨胀为重量级锁.轻量级锁是使用CAS操作完成的加锁解锁过程.虚拟机的对象头中有Mark Word,其中有两位用来存储锁标志位,代码进入同步块时,如果同步对象没有被锁定,虚拟机现在栈帧中建立一个锁记录,来存储锁对象目前的Mark Word的拷贝,然后虚拟机使用CAS操作将对象的Mark Word更新为指向锁记录的指针.如果更新成功了,这个线程就拥有了这个对象锁,否则,先检查Mark Word是否指向当前线程的栈帧,如果是直接进入同步块执行,否则说明锁已经被其他线程抢占了.

偏向锁是,在无竞争的情况下把整个同步都消除掉,连CAS操作都不做了.意思是这个所锁会偏向与第一个获得它的线程,只要这个锁没有被其他线程获取,则持有偏向锁的线程将永远不需要同步.线程第一次获取锁时,对象头中的标志位设置为偏向模式,使用CAS将线程ID记录在Mark Word中,如果CAS成功,持有偏向锁的线程之后都不需要进行同步操作.当有另一个线程尝试获取锁时,偏向模式结束.


2,ReentrantLock实现原理

ReentrantLock是基于AQS实现的,在AQS内部会保存一个状态变量state,通过CAS修改该变量的值,修改成功的线程表示获取到该锁,没有修改成功,或者发现状态state已经是加锁状态,则创建一个代表当前线程的结点加入到等待队列的尾部,如果前趋结点waitStuatus状态是SIGNAL,线程可以大胆挂起等待被唤醒,如果不是,向前遍历跳过被取消的结点,直到找到一个没有被取消的结点为止,将找到的这个结点作为它的前趋结点,将找到的这个结点的waitStatus位设置为SIGNAL,返回false表示线程不应该被挂起。

ReentrantLock增加了一些高级功能:

1,可中断:

当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情,可中断特性对处理执行时间非常长的同步块很有帮助.

2,公平锁: 

因为synchroized是非公平的,ReentrantLock有公平和非公平锁(默认是非公平锁),所以公平锁是和sychronized的区别.

指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来一次获得锁.

3,锁可绑定多个条件:

指一个ReentrantLock对象可以同时绑定多个Condition对象.



原创粉丝点击