一、ReentrantLock是什么?
jdk1.5新增了并发包,里面包含Lock接口,与synchronized关键字一样能实现同步功能,但相比synchronized,Lock更加灵活,可以手动获取、释放锁,而ReentrantLock就是Lock的一个实现类。
二、基本使用
1、可重入锁
ReentrantLock从字面意思翻译就是可重入锁,那什么是可重入锁?简单来说就是某个线程获取改锁后,可以重复的进入改锁锁住的代码。ReentrantLock也是可重入锁,但是要注意的是,因为ReentrantLock需要自己手动加锁、解锁,所以加锁几次就必须解锁几次,不然其他线程就没法获取资源。
public class Main6 {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
f1(lock);
}
public static void f1(ReentrantLock lock){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "第1次");
f2(lock);
}finally {
lock.unlock();
}
}
public static void f2(ReentrantLock lock){
try {
lock.lock(); // 这里再次加锁
System.out.println(Thread.currentThread().getName() + "第2次");
}finally {
lock.unlock();
}
}
}
输出:
main第1次
main第2次
2、非公平锁与公平锁
非公平锁就是多个线程抢夺资源时,不分先来后到,只拼手速,算抢到算谁的,ReentrantLock默认情况下就是非公平锁。
public class Main1 {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(() -> {
for (int i = 0; i < 20; i++) {
ticket.sale();
}
},"A").start();
new Thread(() -> {
for (int i = 0; i < 20; i++) {
ticket.sale();
}
},"B").start();
new Thread(() -> {
for (int i = 0; i < 20; i++) {
ticket.sale();
}
},"C").start();
}
}
class Ticket{
private int count = 20;
// 默认非公平锁
private ReentrantLock lock = new ReentrantLock();
public void sale(){
try {
lock.lock();
if(count > 0){
count--;
System.out.println(Thread.currentThread().getName() + ":卖出1张,剩余" + count);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
可以看出这一轮中B压根都没抢到,输出:
A:卖出1张,剩余19
A:卖出1张,剩余18
A:卖出1张,剩余17
A:卖出1张,剩余16
C:卖出1张,剩余15
C:卖出1张,剩余14
C:卖出1张,剩余13
C:卖出1张,剩余12
C:卖出1张,剩余11
C:卖出1张,剩余10
C:卖出1张,剩余9
C:卖出1张,剩余8
C:卖出1张,剩余7
C:卖出1张,剩余6
C:卖出1张,剩余5
C:卖出1张,剩余4
C:卖出1张,剩余3
C:卖出1张,剩余2
C:卖出1张,剩余1
C:卖出1张,剩余0
那公平锁就是多个线程抢夺资源时,会按照你请求获取锁的时间先来后到,能够尽可能的雨露均沾。ReentrantLock设置成公平锁只需要在构造方法传入true,表示当前是公平锁。所以更改上述代码:
class Ticket{
private int count = 20;
// 公平锁
private ReentrantLock lock = new ReentrantLock(true);
public void sale(){
...
}
现在可以看到三个线程均获取到过资源。
A:卖出1张,剩余19
A:卖出1张,剩余18
A:卖出1张,剩余17
A:卖出1张,剩余16
A:卖出1张,剩余15
B:卖出1张,剩余14
C:卖出1张,剩余13
A:卖出1张,剩余12
B:卖出1张,剩余11
C:卖出1张,剩余10
A:卖出1张,剩余9
B:卖出1张,剩余8
C:卖出1张,剩余7
A:卖出1张,剩余6
B:卖出1张,剩余5
C:卖出1张,剩余4
A:卖出1张,剩余3
B:卖出1张,剩余2
C:卖出1张,剩余1
A:卖出1张,剩余0
三、小结
ReentrantLock除了上面提到多的是可重入锁、公平锁、非公平锁外,它也是独占锁,独占锁就是任何时候都只有一个线程能得到锁,那ReentrantLock与synchronized的区别:
- 性能
目前优化后,synchronized与ReentrantLock性能其实已经没什么太大区别。 - 灵活性
这个一目了然,ReentrantLock肯定比synchronized更加灵活,自行加锁、解锁。并且synchronized只能是非公平锁,而ReentrantLock可以设定成非公平锁或公平锁。