JUC 即 java.util.concurrent 包,提供了大量的工具类来简化并发编程。
ReentrantLock类是一种新增的加锁方法,其底层是CAS原理,能够在许多场景下代替代synchronized,且具有一些优势。
1 使用方法
使用该方法需要显式加锁和解锁,以下是标准写法。
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
dosomething();
} finally {
lock.unlock();
}
2. 锁的可重入
锁是可重入的,否则会导致死锁。
如下代码,有A、B两个方法,都是同一个锁,如果线程通过调用A方法获取了锁,那紧接着就可以调用B方法。
如果没有这个机制,那么调用A方法后,就无法调B方法,程序就运行不下去了。
- synchronized
public class ReentranceLockSynTest {
synchronized void A(){
System.out.println("A被调用了");
B();
}
synchronized void B(){
System.out.println("B被调用了");
}
public static void main(String[] args) {
new Thread(()->{
new ReentranceLockSynTest().A();
}).start();
}
}
- ReentrantLock同样是可重入的。
public class ReentranceLockTest2 {
Lock lock = new ReentrantLock();
void A() {
try {
lock.lock();
System.out.println("A被调用了");
B();
} finally {
lock.lock();
}
}
void B() {
try {
lock.lock();
System.out.println("B被调用了");
} finally {
lock.lock();
}
}
public static void main(String[] args) {
ReentranceLockTest2 test2 = new ReentranceLockTest2();
new Thread(test2::A,"t1").start();
}
}
2. ReentrantLock的特性
2.1 trylock
和synchronized不同,ReentrantLock可以设置超时时间,如果超出时间就不会等待。
public class TryLockTest {
Lock lock = new ReentrantLock();
void A(){
System.out.println("A begin");
try {
lock.lock();
for(int i=0;i<10;i++) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("m1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
lock.unlock();
}
}
void B(){
System.out.println("B begin");
try {
lock.tryLock(2,TimeUnit.SECONDS);
System.out.println("m2 get lock");
}
catch (InterruptedException e) {
System.out.println("B ,太久了,我不等了");
}
finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
TryLockTest test = new TryLockTest();
new Thread(test::A,"t1").start();
Thread.sleep(1000);
new Thread(test::B,"t2").start();
}
}
运行结果显示,当B线程等待三秒后,就没有继续等待,放弃了加锁。
2.2 可以设置公平锁或非公平锁
synchronized锁只能是非公平锁。非公平锁意味着线程用抢占的方式去抢锁,跟等多久没有关系。公平锁意味着等待时间越久的线程有更高的优先级。
Lock lock = new ReentrantLock(true);
- 可以接收interrupt通知,这一点在《JAVA多线程基础篇 三、如何优雅结束一个线程》有介绍。
lock.lockInterruptibly();
总结
ReentrantLock是具有更多自定义功能的锁,能够重入、可以设置超时时间、能够接收打断信息、以及设置公平锁。
ReentrantLock的加锁与解锁是有标准写法的,比须在finally块中进行关闭。
多线程系列在github上有一个开源项目,主要是本系列博客的实验代码。
https://github.com/forestnlp/concurrentlab
如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。
您的支持是对我最大的鼓励。