【专栏锁】ReentrantLock和Synchronized以及锁升级


相同点

  • 都是加锁方式同步;
  • 都是重入锁;
  • 都是阻塞式的同步;

不同点

比较方面SynChronizedReentrantLock(实现了 Lock接口)
原始构成它是java语言的关键字,是原生语法层面的互斥,需要jvm实现它是JDK 1.5之后提供的API层面的互斥锁类
实现通过JVM加锁解锁api层面的加锁解锁,需要手动释放锁。
代码编写采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用,更安全,而ReentrantLock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。需要lock()和unlock()方法配合try/finally语句块来完成,
灵活性锁的范围是整个方法或synchronized块部分Lock因为是方法调用,可以跨方法,灵活性更大
等待可中断

不可中断,除非抛出异常(释放锁方式:

        1.代码执行完,正常释放锁;

        2.抛出异常,由JVM退出等待)

持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,(方法:

                 1.设置超时方法 tryLock(long timeout, TimeUnit unit),时间过了就放弃等待;

                  2.lockInterruptibly()放代码块中,调用interrupt()方法可中断,而synchronized不行)
 

是否公平锁非公平锁两者都可以,默认公平锁,构造器可以传入boolean值,true为公平锁,false为非公平锁,


底层原理

  • Synchronized

Synchronized进过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。

monitorenter :
每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权

monitorexit:
执行monitorexit的线程必须是objectref所对应的monitor的所有者。
指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个
monitor 的所有权

  • ReentrantLock:

CAS+CLH队列来实现。它支持公平锁和非公平锁,两者的实现类似。
CAS:Compare and
Swap,比较并交换。CAS有3个操作数:内存值V、预期值A、要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。该操作是一个原子操作,被广泛的应用在Java的底层实现中。在Java中,CAS主要是由sun.misc.Unsafe这个类通过JNI调用CPU底层指令实现。
CLH队列:带头结点的双向非循环链表,为什么用双向而不用单向是因为:独占模式下需要查看上一个节点是否是首节点;加上前一个节点释放锁后要唤醒下一个节点 就用到了node,pre 和node.next



锁升级

详情:详情点击这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

抵制平庸 拥抱变化

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值