ReentrantLock是独占可重入锁,所谓重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的。
synchronized 和 ReentrantLock 都是可重入锁。
可重入锁的意义在于防止死锁。
实现原理是通过为每个锁关联一个请求计数器和一个占有它的线程。当计数为0时,认为锁是未被占有的;线程请求一个未被占有的锁时,JVM将记录锁的占有者,并且将请求计数器置为1 。
如果同一个线程再次请求这个锁,计数将递增;
每次占用线程退出同步块,计数器值将递减。直到计数器为0,锁被释放。
使用ReentrantLock可实现公平锁与非公平锁。
公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。
优点:所有的线程都能得到资源。
缺点:吞吐量会下降很多,队列里面除了第一个线程,其他的线程都会阻塞,cpu唤醒阻塞线程的开销会很大。
非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。
优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,会减少唤起线程的数量。
缺点:可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁。
代码如下:
package com.example.multithread.ReentrantLock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author liujy
* @description 可重入锁实现公平锁与非公平锁
* @since 2020-12-29 11:03
*/
public class ReentrantLockTest {
// Lock lock = new ReentrantLock();默认实现的是非公平锁
// 非公平锁
// private static Lock lock = new ReentrantLock(false);
// 公平锁
private static Lock lock = new ReentrantLock(true);
public static void test() {
for (int i = 0; i < 2; i++) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " get lock");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
// System.out.println(Thread.currentThread().getName() + " release lock");
}
}
}
public static void main(String[] args) {
new Thread(() -> test(), "kacey").start();
new Thread(() -> test(), "maria").start();
new Thread(() -> test(), "tom").start();
new Thread(() -> test(), "chris").start();
}
}
公平锁运行结果如下:
kacey get lock
maria get lock
tom get lock
chris get lock
kacey get lock
maria get lock
tom get lock
chris get lock
非公平锁运行结果如下:
kacey get lock
kacey get lock
maria get lock
maria get lock
tom get lock
tom get lock
chris get lock
chris get lock