一、概述
同步代码块/同步方法具有的功能Lock都具有,另外ReetranttLock具有其他功能。例如公平锁、响应中断、获取锁时限时等待、结合Condition实现等待机制。
ReetranttLock是可重入锁的独占锁。比起synchronized功能更加丰富,实现公平锁实现、支持中断响应以及实现获取锁限时等待等等。可以配合一个或多个Condition条件方便等待通知机制。(面试的时候回答这个,可以再扯一扯synchronized的优化机制、公平锁非公平锁、死锁的产生以及解决等相关知识)
二、实现公平锁
https://blog.csdn.net/cgj296645438/article/details/79442675
公平锁:先来先服务,可以防止饥饿情况出现。非公平所则随机分配锁的使用权,性能更好但是会有饥饿情况。
//公平 ReentrantLock lock = new ReentrantLock(true); //非公平 ReentrantLock lock = new ReentrantLock(); ReentrantLock lock = new ReentrantLock(false);
二、响应中断
synchronized实现锁时,阻塞在锁上的线程除非获取锁否则将一直等待下去,也就是说这种无限等待获取锁的行为无法被中断。ReetranttLock给我们提供了一个可以响应中断的获取锁的方法lockInterruptibly(),可以用来解决死锁问题。
package com.reentrantLock; import java.util.concurrent.locks.ReentrantLock; /** * @author Millet * @date 2020/3/31 12:00 */ public class Main { private static ReentrantLock lock1 = new ReentrantLock(); private static ReentrantLock lock2 = new ReentrantLock(); public static void main(String[] args) { final Thread t1 = new Thread(new Runnable() { @Override public void run() { try { lock1.lockInterruptibly(); System.out.println(Thread.currentThread().getName()+"获得了锁1"); Thread.sleep(500); lock2.lockInterruptibly(); System.out.println(Thread.currentThread().getName()+"获得了锁2"); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock1.unlock(); lock2.unlock(); } } },"t1"){}; Thread t2 = new Thread(new Runnable() { @Override public void run() { try { lock2.lockInterruptibly(); System.out.println(Thread.currentThread().getName()+"获得了锁2"); Thread.sleep(500); lock1.lockInterruptibly(); System.out.println(Thread.currentThread().getName()+"获得了锁1"); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock1.unlock(); lock2.unlock(); } } },"t2"){}; t1.start(); t2.start();
new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } t1.interrupt(); } }).start(); } }
出现死锁时,直接中断,抛出异常中断死锁。
三、获取锁时限时等待
提供了获取锁时限时等待的方法tryLock(),可以用来解决死锁问题。
/** *timeout:等待获取锁的时间 *unit:时间单位
不写参数则立即返回是否获取锁 */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); }
package com.reentrantLock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** * @author Millet * @date 2020/3/31 14:18 */ public class Main2 { private static ReentrantLock lock1 = new ReentrantLock(); private static ReentrantLock lock2 = new ReentrantLock(); public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { try { if(lock1.tryLock(5, TimeUnit.SECONDS)){ System.out.println(Thread.currentThread().getName()+"获得了锁1"); Thread.sleep(500); if(lock2.tryLock(5, TimeUnit.SECONDS)) System.out.println(Thread.currentThread().getName()+"获得了锁2"); } } catch (InterruptedException e) { e.printStackTrace(); }finally { if (lock1.isLocked()) lock1.unlock(); if (lock2.isLocked()) lock2.unlock(); } } },"t1"){}; Thread t2 = new Thread(new Runnable() { @Override public void run() { try { if(lock2.tryLock(5, TimeUnit.SECONDS)){ System.out.println(Thread.currentThread().getName()+"获得了锁2"); Thread.sleep(500); if(lock1.tryLock(5, TimeUnit.SECONDS)) System.out.println(Thread.currentThread().getName()+"获得了锁1"); } } catch (InterruptedException e) { e.printStackTrace(); }finally { if (lock1.isLocked()) lock1.unlock(); if (lock2.isLocked()) lock2.unlock(); } } },"t2"){}; t1.start(); t2.start(); } }
四、结合Condition实现等待通知机制
使用synchronized结合Object的wait和notify可以实现线程间的等待通知机制。ReentrantLock结合Condition同样可以实现这个功能。