0
点赞
收藏
分享

微信扫一扫

synchronized与Lock区别与选择

synchronized与Lock相同点

  1. 都可以用于保证线程和资源安全
  2. 都可以保证可见性,锁的可见性,不同于volatile

对于 synchronized 而言,线程 A 在进入 synchronized 块之前或在 synchronized 块内进行操作,对于后续的获得同一个 monitor 锁的线程 B 是可见的,也就是线程 B 是可以看到线程 A 之前的操作的,这也体现了 happens-before 针对 synchronized 的一个原则
synchronized与Lock区别与选择
而对于 Lock 而言,它和 synchronized 是一样,都可以保证可见性,如图所示,在解锁之前的所有操作对加锁之后的所有操作都是可见的
synchronized与Lock区别与选择

  1. 都是可重入锁

这里的 ReentrantLock 是 Lock 接口的一个最主要的实现类,在对比 synchronized 和 Lock 的时候,也会选择 Lock 的主要实现类来进行对比。==可重入指的是某个线程如果已经获得了一个锁,现在试图再次请求这个它已经获得的锁,如果它无需提前释放这个锁,而是直接可以继续使用持有的这个锁,那么就是可重入的==。如果必须释放锁后才能再次申请这个锁,就是不可重入的。而 synchronized 和 ReentrantLock 都具有可重入的特性

synchronized与Lock的区别

  • 用法

synchronized用于方法上和和代码块,不指定锁表示this,也可以指定对象;Lock只能使用在方法内显示指定lock unlock,并且需要手动释放锁,一般在finally中释放锁,防止发生死锁
synchronized无需手动释放锁,Lock需要手动释放锁
synchronized不可中断,Lock可以通过调用lockInterruptibly中断锁
synchronized获取不到锁一直阻塞,Lock可以通过tryLock方式尝试获取锁,获取不到锁返回false

  • 多次加锁释放锁顺序不一样
    
    synchronized (A) {
    synchronized (B)
    }

lock.lock(A) {
lock.lock(B) {

}

}


synchronized: 加锁A -> 加锁B -> 释放B -释放A,执行完自动释放锁,由JVM控制

lock: 加锁A -> 加锁B -> 释放A -释放B

- 不够灵活:
一旦 synchronized 锁已经被某个线程获得了,此时其他线程如果还想获得,那它只能被阻塞,直到持有锁的线程运行完毕或者发生异常从而释放这个锁。
Lock 类在等锁的过程中,如果使用的是 lockInterruptibly 方法,那么如果觉得等待的时间太长了不想再继续等待,可以中断退出,也可以用 tryLock() 等方法尝试获取锁,如果获取不到锁也可以做别的事,更加灵活。
- synchronized 锁只能同时被一个线程拥有,但是 Lock 锁没有这个限制
- 原理不同:synchronized 是内置锁,由 JVM 实现获取锁和释放锁的原理,还分为偏向锁、轻量级锁、重量级锁
- 是否可以设置公平/非公平,Lock实现类可以通过参数设置实现,synchronized不可实现,默认非公平锁
- 性能区别:在 Java 5 以及之前,synchronized 的性能比较低,但是到了 Java 6 以后,发生了变化,因为 JDK 对 synchronized 进行了很多优化,比如自适应自旋、锁消除、锁粗化、轻量级锁、偏向锁等,所以后期的 Java 版本里的 synchronized 的性能并不比 Lock 差。

### 选择
1. 如果能不用最好既不使用 Lock 也不使用 synchronized。因为在许多情况下你可以使用 java.util.concurrent 包中的机制,它会为你处理所有的加锁和解锁操作,也就是推荐优先使用工具类来加解锁。
2. 如果 synchronized 关键字适合你的程序, 那么请尽量使用它,这样可以减少编写代码的数量,减少出错的概率。因为一旦忘记在 finally 里 unlock,代码可能会出很大的问题,而使用 synchronized 更安全。
3. 如果特别需要 Lock 的特殊功能,比如尝试获取锁、可中断、超时功能等,才使用 Lock。

> java学习交流q群:513650703
举报

相关推荐

0 条评论