目录java
ReentrantLock 是Java并发包中提供的一个可重入的互斥锁。ReentrantLock 和 synchronized 在基本用法和行为语义上基本相同,一样具备可重入性。只是 ReentrantLock 增长了一些高级扩展功能,好比,能够实现公平锁,同时也能够实现绑定多个 Condition。并发
可重入性: 一个线程在获取一段使用锁的代码时,能够再次进入这段代码。例如,一个被可重入锁修饰的递归程序,能够重复的获取锁,而不会出现把本身锁死的状况。synchronized 和 ReentrantLock 都具备可重入性。ide
公平锁 / 非公平锁
所谓公平锁,指锁的获取策略相对公平,当多个线程在获取同一个锁时,必须按照锁的申请时间来依次得到锁;非公平锁则不一样。synchronized 是非公平锁,ReentrantLock 默认也是非公平的,可是能够经过带 boolean 参数的构造方法指定使用公平锁,但非公平锁的性能通常要优于公平锁。
synchronized 是 Java 原生的互斥同步锁,使用方便,对于 synchronized 修饰的方法或同步块,无需再显式释放锁。而 ReentrantLock 作为 API 层面的互斥锁,须要显式地去加锁解锁。采用 Lock ,必须主动去释放锁,而且在发生异常时,不会自动释放锁。所以通常来讲,使用 Lock 必须在 try{}catch{} 块中进行,而且将释放锁的操做放在 finally 块中进行,以保证锁必定被被释放,防止死锁的发生。函数
class Demo{ private final ReentrantLock lock = new ReentrantLock(); public void method(){ lock.lock(); // 加锁 try{ // to do... }finally { lock.unlock(); // 释放锁 } } }
/** * Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); }
/** * Creates an instance of {@code ReentrantLock} with the * given fairness policy. * * @param fair {@code true} if this lock should use a fair ordering policy */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
public void lock() { sync.acquire(1); //代理到Sync的lock方法上 }
Sync的lock方法是抽象的,实际的lock会代理到FairSync或是NonFairSync上(根据用户的选择来决定,公平锁仍是非公平锁)oop
public void unlock() { sync.release(1); }
释放锁,调用sync的release方法。源码分析
public void method(){ if(lock.tryLock()){ try{ // to do... }finally { lock.unlock(); } }else { // 若是不能获取锁,则作其余事情 } }
tryLock()方法是有返回值的,它表示用来尝试获取锁,若是获取成功,则返回true,若是获取失败(即锁已被其余线程获取),则返回false。性能
public Condition newCondition() { return sync.newCondition(); }
获取一个conditon,ReentrantLock支持多个Conditionui
/* * 编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每一个线程将本身的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。 * 如:ABCABCABC…… 依次递归 */ class AlternateDemo{ private int num = 1; // 标记当前正在执行的线程 private ReentrantLock lock = new ReentrantLock(); private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); /** * * @param totalLoops 循环第几轮 */ public void loopA(int totalLoops){ lock.lock(); try{ if(num != 1){ condition1.await(); } System.out.println(Thread.currentThread().getName() + "\t" + totalLoops); num = 2; condition2.signal(); }catch (Exception e){ }finally { lock.unlock(); } } public void loopB(int totalLoops){ lock.lock(); try{ if(num != 2){ condition2.await(); } System.out.println(Thread.currentThread().getName() + "\t" + totalLoops); num = 3; condition3.signal(); }catch (Exception e){ }finally { lock.unlock(); } } public void loopC(int totalLoops){ lock.lock(); try{ if(num != 3){ condition3.await(); } System.out.println(Thread.currentThread().getName() + "\t" + totalLoops); num = 1; condition1.signal(); }catch (Exception e){ }finally { lock.unlock(); } } } public class Main { public static void main(String[] args) { AlternateDemo alternateDemo = new AlternateDemo(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { alternateDemo.loopA(i); } } }, "A").start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { alternateDemo.loopB(i); } } }, "B").start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { alternateDemo.loopC(i); System.out.println("----------------------"); } } }, "C").start(); } }
代码分析:三个线程A、B、C分别调用10次打印,只需想办法控制三个现成的执行顺序。
若线程A先获取锁,直接打印。
若线程B先获取锁,B会被阻塞,释放锁后由A、C争夺。
若线程C先获取锁,C会被阻塞,释放锁后由A、B争夺。
使用一个变量来维持获取锁的顺序,分别是线程A、线程B、线程Cthis