ReentrantLock
可重入指任意线程在获取到锁之后可以再次获取到该锁而不会被该锁阻塞。
可重入锁指支持可以重入的锁,该锁可以支持一个线程对资源的重复加锁。
线程再次获取锁问题: 锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则可以再次获取成功。
锁的最终释放问题:线程重复n此获取了锁,随后在第n次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求对于获取进行计数自增,计数表示当前锁被线程重复获取的次数,而锁被释放时,计数自减,当计数等于0时表示该锁成功释放。
主要成员
ReentrantLock实现了Lock接口,并在内部创建了一个内部类Sync继承了AQS类。在Sync上又延伸出公平锁和非公平锁。在绝对时间上,先对锁进行获取请求一定先获取到,则该锁是公平的,反之,锁是非公平锁。
构造函数
ReentrantLock的构造函数如下
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
Sync类
sync继承了AbstractQueuedSynchronizer。主要还是依托于AQS进行锁的管理。初识AQS
存在如下方法和作用如下:
方法名 | 说明 |
---|
void lock(); | 获取锁,由子类实现 | boolean nonfairTryAcquire(int acquires) | 非公平方式获取同步状态 true成功获取;false获取失败 | boolean tryRelease(int releases) | 释放状态,true成功释放;false释放失败 | boolean isHeldExclusively() | 判断资源是否被当前线程占有 true代表当前线程占用,false代表其他线程占用 | ConditionObject newCondition() | 创建一个新的condition对象 | Thread getOwner() | 或者当前占用线程,null代表为有占用者线程 | int getHoldCount() | 返回目前占用的状态(次数) 0代表未被占用 | boolean isLocked() | 资源是否被锁了(占用),true已被占用,false未被占用 | void readObject(java.io.ObjectInputStream s) | 自定义反序列化逻辑 |
源码部分
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
abstract void lock();
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0);
}
}
NonfairSync 非公平锁
继承了Sync,提供了非公平方式的获取方法lock() 。
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
FairSync公平锁
同样继承了Sync,提供了公平方式的获取方法lock() 和tryAcquire(int acquires) 。
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
示例分析
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FairAndUnfairTest {
private static Lock fairLock = new ReentrantLock2(true);
private static Lock unfairLock = new ReentrantLock2(false);
public static void main(String[] args) throws InterruptedException {
System.out.println("非公平锁");
unfair();
System.out.println("公平锁");
fair();
}
public static void unfair() throws InterruptedException {
testLock(unfairLock);
}
public static void fair() throws InterruptedException {
testLock(fairLock);
}
private static void testLock(Lock lock) throws InterruptedException {
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(new Job(lock)) {
@Override
public String toString() {
return getName();
}
};
thread.setName("t_" + i);
thread.start();
}
Thread.sleep(11000);
}
private static class Job extends Thread {
private Lock lock;
public Job(Lock lock) {
this.lock = lock;
}
@Override
public void run() {
for (int i = 0; i < 2; i++) {
lock.lock();
try {
s();
Thread.sleep(1000);
System.out.println("获取锁的当前线程[" + Thread.currentThread().getName() + "],第" + (i + 1) + "次执行, 同步队列中的线程" + ((ReentrantLock2) lock).getQueueThreads() + "");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
private void s(){
lock.lock();
try {
System.out.println("获取锁的当前线程[" + Thread.currentThread().getName() + "],重入执行, 同步队列中的线程" + ((ReentrantLock2) lock).getQueueThreads() + "");
} finally {
lock.unlock();
}
}
}
private static class ReentrantLock2 extends ReentrantLock {
public ReentrantLock2(boolean fair) {
super(fair);
}
public Collection<Thread> getQueueThreads() {
List<Thread> threadList = new ArrayList<>(super.getQueuedThreads());
Collections.reverse(threadList);
return threadList;
}
}
}
执行结果
非公平锁
获取锁的当前线程[t_0],重入执行, 同步队列中的线程[t_1, t_2]
获取锁的当前线程[t_0],第1次执行, 同步队列中的线程[t_1, t_2]
获取锁的当前线程[t_0],重入执行, 同步队列中的线程[t_1, t_2]
获取锁的当前线程[t_0],第2次执行, 同步队列中的线程[t_1, t_2]
获取锁的当前线程[t_1],重入执行, 同步队列中的线程[t_2]
获取锁的当前线程[t_1],第1次执行, 同步队列中的线程[t_2]
获取锁的当前线程[t_1],重入执行, 同步队列中的线程[t_2]
获取锁的当前线程[t_1],第2次执行, 同步队列中的线程[t_2]
获取锁的当前线程[t_2],重入执行, 同步队列中的线程[]
获取锁的当前线程[t_2],第1次执行, 同步队列中的线程[]
获取锁的当前线程[t_2],重入执行, 同步队列中的线程[]
获取锁的当前线程[t_2],第2次执行, 同步队列中的线程[]
公平锁
获取锁的当前线程[t_0],重入执行, 同步队列中的线程[]
获取锁的当前线程[t_0],第1次执行, 同步队列中的线程[t_1, t_2]
获取锁的当前线程[t_1],重入执行, 同步队列中的线程[t_2, t_0]
获取锁的当前线程[t_1],第1次执行, 同步队列中的线程[t_2, t_0]
获取锁的当前线程[t_2],重入执行, 同步队列中的线程[t_0]
获取锁的当前线程[t_2],第1次执行, 同步队列中的线程[t_0, t_1]
获取锁的当前线程[t_0],重入执行, 同步队列中的线程[t_1, t_2]
获取锁的当前线程[t_0],第2次执行, 同步队列中的线程[t_1, t_2]
获取锁的当前线程[t_1],重入执行, 同步队列中的线程[t_2]
获取锁的当前线程[t_1],第2次执行, 同步队列中的线程[t_2]
获取锁的当前线程[t_2],重入执行, 同步队列中的线程[]
获取锁的当前线程[t_2],第2次执行, 同步队列中的线程[]
- 什么是可重入,什么是可重入锁? 它用来解决什么问题?
- ReentrantLock的核心是AQS,那么它怎么来实现的,继承吗? 说说其类内部结构关系。
- ReentrantLock是如何实现公平锁的?
- ReentrantLock是如何实现非公平锁的?
- ReentrantLock默认实现的是公平还是非公平锁?
- 使用ReentrantLock实现公平和非公平锁的示例?
- ReentrantLock和Synchronized的对比?
|