1.与synchronized不同点:
- 可中断
- 可以设置超时时间
- 可以设置公平锁,公平锁就是为了解决饥饿线程,让线程排队,先进先出,先来的线程先执行。
- 支持多个条件变量
2.与synchronized相同点都支持锁的可重入。
基本格式:
//获取锁 reentrantLock.lock(); try {} finally {//必须释放锁reentrantLock.unlock(); }
可重入
同一个线程如果首次获得了这把锁,因为它是这把锁的拥有者,因此有权利再次获取这把锁。
如果是不可重入锁,那么第二次获得锁时,自己也会被锁挡住。
@Slf4j
public class ReentrantLockDemo {private static ReentrantLock reentrantLock = new ReentrantLock();public static void main(String[] args) {//获取锁reentrantLock.lock();try {log.info("调用main方法...");method1();} finally {//必须释放锁reentrantLock.unlock();}}public static void method1() {reentrantLock.lock();try {log.info("调用method1方法...");method2();}finally {reentrantLock.unlock();}}public static void method2() {reentrantLock.lock();try {log.info("调用method2方法...");}finally {reentrantLock.unlock();}}
}
可被中断
lockInterruptibly方法表示可被打断的锁
lokc方法加锁表示不可被打断的锁
可打断的锁,可以防止死锁。
@Slf4j
public class Reen {private static ReentrantLock reentrantLock = new ReentrantLock();public static void main(String[] args) {Thread t1 = new Thread(() -> {try {log.info("尝试获取锁....");//lockInterruptibly可被打断的锁reentrantLock.lockInterruptibly();} catch (InterruptedException e) {e.printStackTrace();log.info("等待获取锁的线程被打断....返回");return;}try {log.info("获取到了锁...");}finally {reentrantLock.unlock();}}, "t1");//main线程获取锁reentrantLock.lock();t1.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}log.info("打断线程t1....");t1.interrupt();}
}
可以设置超时时间
tryLock方法,设置超时时间,避免长时间等待,防止死锁。
tryLock方法不设置超时时间参数表示获取不到锁立刻返回。
@Slf4j
public class ReenDemo {private static ReentrantLock reentrantLock = new ReentrantLock();public static void main(String[] args) {Thread t1 = new Thread(() -> {//尝试获取锁,时间是立刻返回log.info("尝试获取锁...");try {if(!reentrantLock.tryLock(2, TimeUnit.SECONDS)) {log.info("尝试获取锁失败,返回...");return;}log.info("尝试获取锁成功...");} catch (InterruptedException e) {e.printStackTrace();log.info("尝试获取锁被打断,返回...");return;}try {}finally {reentrantLock.unlock();}}, "t1");reentrantLock.lock();t1.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}try {}finally {reentrantLock.unlock();}}
}
解决哲学家吃饭的死锁问题:
public class DeadLockDemo {public static void main(String[] args) {Chopstick chopstick1 = new Chopstick("1");Chopstick chopstick2 = new Chopstick("2");Chopstick chopstick3 = new Chopstick("3");Chopstick chopstick4 = new Chopstick("4");Chopstick chopstick5 = new Chopstick("5");new Philosopher("哲学家1", chopstick1, chopstick2).start();new Philosopher("哲学家2", chopstick2, chopstick3).start();new Philosopher("哲学家3", chopstick3, chopstick4).start();new Philosopher("哲学家4", chopstick4, chopstick5).start();new Philosopher("哲学家5", chopstick5, chopstick1).start();}
}@Slf4j
class Philosopher extends Thread {//左边的筷子Chopstick left;//右边的筷子Chopstick right;public Philosopher(String name, Chopstick left, Chopstick right) {super(name);//设置线程名称this.left = left;this.right = right;}@Overridepublic void run() {while (true) {//这里意思是一位哲学家获取了两根筷子后吃完饭,又重新开始下一轮...//解决死锁问题,使用ReentrantLock.tryLock方法,避免长时间等待不释放锁的情况if(left.tryLock()) {try {if(right.tryLock()) {try {eat();}finally {right.unlock();}}}finally {left.unlock();}}// synchronized (left) {
// synchronized (right) {
// eat();
// }
// }}}private void eat() {log.info("eat...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}/*** 筷子类*/
class Chopstick extends ReentrantLock{//名称private String name;public Chopstick(String name) {this.name = name;}@Overridepublic String toString() {return "Chopstick{" +"name='" + name + '\'' +'}';}
}
公平锁
ReentrantLock模式是非公平锁,synchronized也是非公平锁。但是ReentrantLock可以设置为公平锁。new ReentrantLock(true); 公平锁可以防止饥饿锁。按照先进先出的规则。公平锁会降低并发度。