synchronized 与 lock 的大致区别

自我记录 自我记录。。。
两者的比较大致可以从这么几个方面来进行:
1、两者的实现层面
synchronized实现层面是在jvm上,而lock则是一个类,一个亲儿子,一个干儿子
2、两者的获取以及释放方式
synchronized只要进入到它包围的代码块里,那么自动获取锁,当运行完被包围的代码,或者出现异常,那么会自动释放锁
而lock则需要手动获取,并且需要自己释放锁。
另外还有:
synchronized:可重入 不可中断 不公平
lock:可重入 可中断 公平/不公平

synchronized:底层有这个玩意 monitorenter + montiorexit + monitorext
这里写图片描述

有两个monitorexit,因为有两中退出方式,一种是正常退出,一种是非正常退出(报异常)

对于锁的优化,稍微记录点:
轻量级锁不是用来替换重量级锁,它本意是用来在没有线程竞争的情况下,减少重量级锁带来的性能消耗,它适用于线程交替替换的过程,一旦有线程产生了竞争,那么轻量级锁就会升级为重量级锁

偏向锁主要是用来在无线程竞争的情况下,减少不必要的轻量锁执行路径

轻量锁主要是用于线程交替的时候
偏向锁用于只有一个线程跑同步块的时候

偏向锁获取的过程:
首先判断状态位,mark word偏向锁的标识是否为1,锁标志位是否为01,确实是否可偏向
如果是偏向的,看测试线程的id是否是当前线程
如果是那么执行代码
如果不是,通过CAS操作竞争锁,成功了,则获取锁,失败了,则到达下一个全局安全点时,锁升级为轻量锁

偏向锁的释放,线程不会主动释放偏向锁,只有当出现线程竞争时才会释放,有两种情况,一种是释放了,一种是升级了

其他锁优化:
适应性自旋:线程获取轻量级锁时,需要进行CAS获取锁,如果获取失败,那么会自旋等哈子,这么一直自旋下去,消耗CPU,因此指定自旋次数,譬如10次,如果这次自旋中获取了锁,那么增加其自旋次数,如果获取失败了,那么减少其自旋次数
锁粗化:如果几段代码是连续的,那么小锁会被弄成大锁
锁消除:如果在局部代码块内执行,那么不用加锁,因为不存在线程不安全的问题

重量级锁:线程阻塞
轻量级锁:消耗CPU
偏向锁:存在锁竞争,那么会消耗额外资源

jdk对synchronized进行的优化,详细点的可以看这里:
http://www.cnblogs.com/paddix/p/5405678.html

### Java 中 synchronized 的升级机制及过程 #### 偏向 (Biased Locking) 当一个线程访问同步块并获取时,JVM会标记此对象为偏向该线程的对象。如果后续由同一个线程再次访问这个同步块,则无需重新加和解操作,只需简单地验证当前线程是否仍然拥有偏向即可[^1]。这种机制减少了频繁进入退出同步块所带来的性能开销。 #### 轻量级 (Lightweight Locking) 一旦有第二个线程尝试访问被第一个线程持有的时,就会触发轻量级模式。在此阶段,JVM不会立即将降级为重量级;而是采用一种称为自旋的方式让后来的竞争者循环等待直到原持有者释放为止[^2]。这种方式适用于那些定时间很短的情况,因为避免了操作系统层面昂贵的上下文切换成本。 #### 自旋 (Spin Lock) 作为轻量级的一部分,自旋是一种忙等待技术,即在一定次数内不断重试以期获得所需的资源而不停留在队列里排队等候调度器安排执行机会[^3]。对于大多数应用来说,默认情况下只有短暂时间段内的争用才会启用自旋策略,超过设定阈值则转为传统阻塞方式处理请求。 #### 重量级 (Heavyweight Locking) 最终,在高并发环境下或者长时间占用的情况下,synchronized 将退化成基于操作系统互斥量(mutex lock)实现的传统重量级形式。此时涉及到用户态核心态之间的转换以及可能伴随而来的时间片分配等问题,因此其代价相对较高[^4]。 综上所述,`synchronized` 的升级路径大致遵循如下顺序:**偏向 -> 轻量级(含自旋) -> 重量级**。每一步骤都旨在适应特定条件下的最优解决方案,从而达到既保障数据一致性又兼顾效率的目的。 ```java public class SynchronizationExample { private final Object monitor = new Object(); public void methodA() { synchronized(monitor){ System.out.println("Executing Method A"); } } public static void main(String[] args) throws InterruptedException{ SynchronizationExample example=new SynchronizationExample(); Thread t1= new Thread(()->{example.methodA();}); Thread t2= new Thread(()->{example.methodA();}); t1.start();t2.start(); t1.join();t2.join(); } } ``` 上面展示了一个简单的例子来演示两个线程如何竞争同一把监视器上的,并经历潜在的不同类型的状态变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值