在Java中,有两种常用的锁:synchronized(内置锁)和ReentrantLock(可重入锁),两者作用相同,但也有很多区别,今天就来聊聊。区别一:用法不同Synchronized可以用来修饰普通方法、静态方法和代码块,而ReentrantLock只能用在代码块上。Synchronized基本使用使用synchronized修饰代码块:publicvoidmethod(){//锁定代码synchronized(this){//...}}ReentrantLock基本使用ReentrantLock在使用之前需要创建一个ReentrantLock对象,然后使用lock方法给它加锁,用完之后再调用unlock方法释放锁。具体使用如下:publicclassLockExample{//创建锁对象privatefinalReentrantLocklock=newReentrantLock();publicvoidmethod(){//锁操作lock.lock();try{//...}finally{//释放锁lock.unlock();区别2:获取和释放锁的不同方式synchronized会自动加锁和释放锁,当进入synchronized修改后的代码块会自动加锁,离开synchronized代码段后会自动释放锁,如图下图中:ReentrantLock需要手动加锁和释放,如下图:PS:使用ReentrantLock时要注意,unlock释放锁的操作一定要放在finally中,否则锁可能会被全部占用时间,导致其他线程一直阻塞。区别三:锁的种类不同。Synchronized是非公平锁,而ReentrantLock既可以是公平锁也可以是非公平锁。默认情况下,ReentrantLock是非公平锁。查看源码可以看到:使用newReentrantLock(true)创建公平锁。查看源码可以看到:区别四:对中断的响应不同。ReentrantLock可以使用lockInterruptibly来获取锁和响应中断命令,而synchronized不能响应中断,即如果发生死锁,使用synchronized会一直等待,而使用ReentrantLock可以响应中断和释放锁,从而解决问题死锁的,比如下面这个ReentrantLock响应中断的例子:importjava.util.concurrent。TimeUnit;导入java.util.concurrent.locks.Lock;导入java.util.concurrent.locks.ReentrantLock;公共类ReentrantLockInterrupt{staticLocklockA=newReentrantLock();静态锁lockB=newReentrantLock();publicstaticvoidmain(String[]args)throwsInterruptedException{//线程1:先获取lockA,然后获取lockBThreadt1=newThread(()->{try{//先获取LockAlockA.lockInterruptibly();//休眠10毫秒TimeUnit.MILLISECONDS.sleep(100);//获取LockBlockB.lockInterruptibly();}catch(InterruptedExceptione){System.out.println("响应中断命令");}finally{//释放锁lockA.unlock();锁B.解锁();System.out.println("线程1执行完成");}});//Thread2:先获取lockB再获取lockAThreadt2=newThread(()->{try{//先获取LockBlockB.lockInterruptibly();//休眠10毫秒TimeUnit.MILLISECONDS.sleep(100);//获取LockAlockA.lockInterruptibly();}catch(InterruptedExceptione){System.out.println("Responsetointerruptcommand");}finally{//释放锁lockB.unlock();lockA.unlock();System.out.println("线程2执行完毕。");}});t1.start();t2.start();TimeUnit.SECONDS.sleep(1);//线程1:执行中断t1.interrupt();}}上面程序的执行结果如下所示:差异5:底层实现不同,Synchronized是通过监视器(Monitor)在JVM层面实现的,而ReentrantLock是通过AQS(AbstractQueuedSynchronizer)程序级API实现的,Synchronized是通过监视器实现的,通过观察编译后的字节码可以得出一个结论,如下图所示:其中monitorenter表示进入monitor,相当于加锁操作,monitorexit表示退出monitor,相当于操作ReentrantLock是通过AQS实现的,通过观察ReentrantLock的源码可以得出结论,核心实现源码如下:总结Synchronized和ReentrantLock都是Java提供的可重入锁。它们之间的主要区别如下:用法不同:synchronized可以用来修饰普通方法、静态方法和代码块,而ReentrantLock只能在代码块中使用。获取和释放锁的机制不同:synchronized自动加锁和释放锁,而ReentrantLock需要手动加锁和释放锁。不同类型的锁:synchronized是非公平锁,而ReentrantLock默认是Unfair锁,也可以手动指定为公平锁。对中断的响应不同:ReentrantLock可以响应中断解决死锁问题,而synchronized不能响应中断。底层实现不同:synchronized是通过monitor在JVM层面实现的,而ReentrantLock是基于AQS实现的。是非自己论,名誉他人论,得失算。公众号:Java面试真题分析面试合集:https://gitee.com/mydb/interview
