并发编程之 ReentrantLock
基本语法
java
// 获取锁
reentrantLock.lock();
try {
// 临界区
} finally {
// 释放锁
reentrantLock.unlock();
}
ReentrantLock——lock()
ReentrantLock 和 Synchronized 一样支持重入锁。
java
public class LockTest3 {
//首先定义一把锁
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
lock1();
}
public static void lock1() {
lock.lock();
try {
log.debug("执行lock1");
//锁重入
lock2();
} finally {
lock.unlock();
}
}
public static void lock2() {
lock.lock();
try {
log.debug("执行lock2");
} finally {
lock.unlock();
}
}
}
ReentrantLock——lockInterruptibly() 锁打断
java
public class LockTest4 {
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
//t2首先获取锁 然后阻塞5s
new Thread(()->{
try {
lock.lock();//获取锁
log.debug("获取锁----");
TimeUnit.SECONDS.sleep(5);
log.debug("t2 5s 之后继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
},"t2").start();
//主要是为了让t2先拿到锁
TimeUnit.SECONDS.sleep(1);
// t1 加锁失败,因为锁已经被 t2 持有
Thread t1 = new Thread(() -> {
try {
lock.lockInterruptibly();
log.debug("t1 获取了锁--执行代码");
} catch (Exception e) {
e.printStackTrace();
log.debug("被打断了没有获取锁");
return;
} finally {
lock.unlock();
}
}, "t1");
t1.start();
//由于t1 可以被打断 故而1s之后打断t1 不在等待t2释放锁了
try {
TimeUnit.SECONDS.sleep(2);
log.debug("主线程------2s后打断t1");
t1.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ReentrantLock——tryLock()
java
public class LockTest5 {
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
log.debug("t1启动---------");
// if 里面也可以添加一个超时时间:lock.tryLock(2,TimeUnit.SECONDS),如果在超时时间外还没有拿到锁,直接返回 false,表示没有拿到锁
if (!lock.tryLock()) {//进入if表示拿不到锁
log.debug("拿不到锁,返回");
return;
}
try {
log.debug("获得了锁");
} finally {
lock.unlock();
}
}, "t1");
//主线程先获取锁
lock.lock();
log.debug("主綫程获得了锁");
t1.start();
try {
TimeUnit.SECONDS.sleep(3);
} finally {
lock.unlock();
}
}
}
ReentrantLock——newCondition() 多个条件解锁
java
public class LockTest6 {
static final ReentrantLock lock = new ReentrantLock();
static boolean isPrettyGril = false; // 女人
static boolean isMoney = false;//工资
//没有女人的 waitSet
static Condition waitpg = lock.newCondition();
// 没有钱的waitSet
static Condition waitm = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
try {
lock.lock();
log.debug("有没有女人[{}]", isPrettyGril);
while (!isPrettyGril) {
log.debug("没有女人!等女人");
try {
waitpg.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("男女搭配干活不累;一下就写完了代码");
}finally {
lock.unlock();
}
}, "jack").start();
new Thread(() -> {
try {
lock.lock();
log.debug("有没有工资[{}]", isMoney);
while (!isMoney) {
log.debug("没有工资!等发工资");
try {
waitm.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("-----卧槽好多钱;一下就写完了代码");
} finally {
lock.unlock();
}
}, "rose").start();
Thread.sleep(1000);
new Thread(() -> {
try {
lock.lock();
isMoney = true;
log.debug("钱来哦了");
waitm.signalAll();
isPrettyGril=true;
log.debug("漂亮小姐姐来了");
waitpg.signal();
}finally {
lock.unlock();
}
}, "boss").start();
}
}
ReentrantLock 总结
假如线程 A 和线程 B 使用同一个锁 LOCK,此时线程 A 首先获取到锁 LOCK.lock(),并且始终持有不释放。如果此时 B 要去获取锁,有四种方式:
LOCK.lock(): 此方式会始终处于等待中,即使调用 B.interrupt()也不能中断,除非线程 A 调用 LOCK.unlock()释放锁。
LOCK.lockInterruptibly(): 此方式会等待,但当调用 B.interrupt()会被中断等待,并抛出 InterruptedException 异常,否则会与 lock()一样始终处于等待中,直到线程 A 释放锁。
LOCK.tryLock(): 该处不会等待,获取不到锁并直接返回 false,去执行下面的逻辑。
LOCK.tryLock(10, TimeUnit.SECONDS):该处会在 10 秒时间内处于等待中,但当调用 B.interrupt()会被中断等待,并抛出 InterruptedException。10 秒时间内如果线程 A 释放锁,会获取到锁并返回 true,否则 10 秒过后会获取不到锁并返回 false,去执行下面的逻辑。