Synchronized和Lock(ReentrantLock)的区别

Synchronized和Lock的区别:Sybchronized编码更简单,锁机制由JVM维护,在竞争不激烈的情况下性能更好;而Lock功能更强大更灵活,竞争激烈时性能更好。

1、两者都是可重入锁:

“可重入锁”的概念是:某个线程已经获得某个锁,可以再次获取锁而不会出现死锁,也就是说可以多次获取相同的锁。比如说一个线程获得了某个对象的锁,此时这个锁还没有释放,当其再次想要获取这个对象的锁时还是可以获取的,如果不可锁重入的话,就会造成死锁。同一个线程每次获取锁,锁的计数器都会自增1,所以要等到锁的计数器下降为0时才能释放锁。
2、synchronized是java内置关键字,在JVM层面,依赖于JVM,而ReentrantLock依赖于API,Lock是一个类。
synchronized 是依赖于 JVM 实现的,前⾯我们也讲到了 虚拟机团队在 JDK1.6 为 synchronized 关键字进⾏了很多优化,但是这些优化都是在虚拟机层⾯实现的,并没有直接暴露给我们。ReentrantLock 是 JDK 层⾯实现的(也就是 API 层⾯,需要 lock() 和 unlock() ⽅法配合try/finally 语句块来完成),所以我们可以通过查看它的源代码,来看它是如何实现的。换句话说,synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),并且加锁次数和释放次数要一样,否则容易造成线程死锁;

3、ReentrantLock比Synchronized增加了一些高级功能:

相⽐synchronized,ReentrantLock增加了⼀些⾼级功能。主要来说主要有三点:1、等待可中断;2、可实现公平锁;3、可实现选择性通知(锁可以绑定多个条件)

  • ReentrantLock提供了⼀种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
  • ReentrantLock可以指定是公平锁还是⾮公平锁。⽽synchronized只能是⾮公平锁。所谓的公平锁就是先等待的线程先获得锁。 ##ReentrantLock默认情况是⾮公平的##,可以通过 ReentrantLock类的ReentrantLock(boolean fair) 构造⽅法来制定是否是公平的。
  • synchronized关键字与wait()和notify()/notifyAll()⽅法相结合##可以实现等待/通知机制##,ReentrantLock类当然也可以实现,但是需要借助于Condition接⼝与newCondition() ⽅法。Condition是JDK1.5之后才有的,它具有很好的灵活性,⽐如可以实现多路通知功能也就是在⼀个Lock对象中可以创建多个Condition实例(即对象监视器),线程对象可以注册在指定的Condition中,从⽽可以有选择性的进⾏线程通知,在调度线程上更加灵活。 在使⽤notify()/notifyAll()⽅法进⾏通知时,被通知的线程是由 JVM 选择的,⽤ReentrantLock类结合Condition实例可以实现“选择性通知” ,这个功能⾮常重要,⽽且是Condition接⼝默认提供的。⽽synchronized关键字就相当于整个Lock对象中只有⼀个Condition实例,所有的线程都注册在它⼀个身上。如果执⾏notifyAll()⽅法的话就会通知所有处于等待状态的线程这样会造成很⼤的效率问题,⽽Condition实例的signalAll()⽅法 只会唤醒注册在该Condition实例中的所有等待线程。如果你想使⽤上述功能,那么选择ReentrantLock是⼀个不错的选择。
    4、synchronized是一种悲观锁,每次都把自己关起来做事,怕被抢;而lock底层是CAS乐观锁的体现,如果被抢了,就重新去拿,很乐观,底层主要靠volatile和CAS实现的。
    5、Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

尽可能去使用synchronized而不要去使用lock,在jdk1.6~jdk1.7的时候,也就是synchronized16、7年的时候,做了很多优化

原文地址:https://www.cnblogs.com/xiaozhengtongxue/p/13701987.html