lock()、tryLock()、tryLock(long time, TimeUnit unit) 和 lockInterruptibly()都是用来获取锁的。
(1) lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。
(2) tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
(3) tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
(4) lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。
1:synchronized无法判断,是否已经获取到锁,而Lock通过tryLock()方法可以判断,是否已获取到锁;
2:Lock可以通过分别定义读写锁提高多个线程读操作的效率。
3:二者的底层实现不一样:synchronized是同步阻塞,采用的是悲观并发策略;Lock是同步非阻塞,采用的是乐观并发策略(底层基于CAS+AQS实现)
1、死锁预防:这个是比较容易忽视的一点
Lock可以选择性的获取锁,如果一段时间获取不到,可以放弃。
synchronized不行,会一根筋一直获取下去。
借助Lock的这个特性,就能够规避死锁,synchronized必须通过谨慎和良好的设计,才能减少死锁的发生。
2、Lock是一个接口,Lock是代码层面的实现;
而synchronized是Java中的关键字,synchronized是内置的语言实现
3、synchronized在发生异常和同步块结束的时候,会自动释放锁;
而Lock必须手动释放, 所以如果忘记了释放锁,一样会造成死锁
4、synchronized底层采用的是objectMonitor;
lock采用的CAS+AQS
5、synchronized是阻塞式加锁;
lock是非阻塞式加锁支持可中断式加锁,支持超时时间的加锁;
6、synchronized在进行加锁解锁时,只有一个同步队列和一个等待队列;
lock有一个同步队列,可以有多个等待队列;
7、synchronized只支持非公平锁;lock支持非公平锁和公平锁;
8、synchronized使用了object类的wait和notify进行等待和唤醒;
lock使用了condition接口进行等待和唤醒(await和signal);
9、与synchronized 不同的是,一旦synchronized 块结束,就会自动释放对someObject的占用。 lock却必须调用unlock方法进行手动释放,为了保证释放的执行,往往会把unlock() 放在finally中进行;
10、trylock会在指定时间范围内试图占用。 如果时间到了,还占用不成功,就选择放弃;
注意: 因为使用trylock有可能成功,有可能失败,所以后面unlock释放锁的时候,需要判断是否占用成功了,如果没占用成功也unlock,就会抛出异常;
11、使用synchronized方式进行线程交互,用到的是同步对象的wait,notify和notifyAll方法;
Lock也提供了类似的解决办法,首先通过lock对象得到一个Condition对象,然后分别调用这个Condition对象的:await, signal,signalAll 方法;
注意: 不是Condition对象的wait,nofity,notifyAll方法,是await,signal,signalAll;
java并发AQS原理_沙漠一只雕得儿得儿的博客-CSDN博客_aqs java
ReentrantLock实现原理及源码分析 - dreamcatcher-cx - 博客园
ReentrantLock的核心,是通过修改AQS中state的值来同步锁的状态,实现了可重入。
ReentrantLock具备公平锁和非公平锁,默认使用非公平锁。实现原理依赖于AQS中的同步队列。
ReentrantLock是一种可重入的,可实现公平性的互斥锁,它的设计基于AQS框架,可重入和公平性的实现逻辑都不难理解,每重入一次,state就加1,当然在释放的时候,也得一层一层释放。至于公平性,在尝试获取锁的时候多了一个判断:是否有比自己申请早的线程在同步队列中等待,若有,去等待;若没有,才允许去抢占。
可重入原理:
ReentrantLock的可重入功能基于AQS的同步状态:state。
其原理大致为:当某一线程获取锁后,将state值+1,并记录下当前持有锁的线程,再有线程来获取锁时,判断这个线程与持有锁的线程是否是同一个线程,如果是,将state值再+1,如果不是,阻塞线程。 当线程释放锁时,将state值-1,当state值减为0时,表示当前线程彻底释放了锁,然后将记录当前持有锁的线程的那个字段设置为null,并唤醒其他线程,使其重新竞争锁。
非公平锁示例图:

公平锁示例图:

加锁过程:
1.先获取state值,若为0,意味着此时没有线程获取到资源,CAS将其设置为1,设置成功则代表获取到排他锁了;
2.若state大于0,肯定有线程已经抢占到资源了,此时再去判断是否就是自己抢占的,是的话,state累加,返回true,重入成功,state的值即是线程重入的次数;
3.其他情况,则获取锁失败。

