什么是ReentrantLock?
1、ReentrantLock可重入锁:一个线程获取了锁,当它想再次想获取锁的时候不用等待可以直接获取锁;
2、公平锁:按请求锁的顺序分配,保证线程会获取锁,性能比公平锁低;
2、非公平锁:不按照请求锁的顺序分配,不保证线程会获取锁,性能比公平锁高;
ReentrantLock是基于AQS,在并发编程中它可以实现公平锁和非公平锁来对共享资源进行同步,
同时,和synchronized异常,ReentrantLock至此可重入,除此之外ReentrantLock在调度上更加灵活,至此丰富的功能。
Lock接口
Lock的意义在于提供了区别于Synchronized的另外一种具有广泛操作的同步方式,它能支持更多灵活的结构
public interface Lock {
/**用于获取锁,假如当前资源被其他线程占用,将会等待直到获取锁*/
void lock();
/**和lock()方法一样,区别在于如果在等待获取锁的时候被中断,将会退出等待,并抛出异常*/
void lockInterruptibly() throws InterruptedException;
/**尝试获取锁,如果获取并立即返回,返回值为boolean代表是否获取锁*/
boolean tryLock();
/**在一段时间内获取锁,假如被终端将会抛出异常*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
/**释放锁*/
void unlock();
/**新建一个绑定在当前Lock上的Condition对象
Condition对象表示一个等待状态
场景:获取锁的线程可能需要等待一些条件的完成才能继续执行
这样他就可以通过await()方法注册在condition对象上进行等待
然后通过condition的signal()方法将其唤醒
可以分组唤醒,丰富线程调度*/
Condition newCondition();
}
ReentrantLock 核心方法
ReentrantLock构造方法
默认实现非公平锁,还可以通过传入一个布尔值选择公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
nonfairTryAcquire()非公平的尝试获取锁
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
/**首先获取status:status为0的话代表当前锁状态为空闲*/
int c = getState();
/**当锁为空闲可以通过一次cas来原子的更改status*/
if (c == 0) {
/**通过cas来更改status的状态*/
if (compareAndSetState(0, acquires)) {
/**如果更改成功就获取了锁,将当前线程改为独占线程,并返回true*/
setExclusiveOwnerThread(current);
return true;
}
}
/**当status不为0的话,就判断当前线程是否为独占线程
可重入性:单个线程执行时候,重新进入同一个子程序,任然是线程安全的,一个线程获取了锁,可以不用等待再次获取锁*/
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
NonfairSync 非公平锁
重写了AQS lock于tryAcquire方法,
非公平锁有两次获取锁的机会,如果获取失败就变成公平锁,在队列中排队
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
/**通过CAS的方式获取锁,如果获取成功,设置为独占状态*/
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
/**获取失败就调用AQS中的acquire方法,在acquire方法中还用一次尝试获取锁*/
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
/**插队尝试获取锁*/
return nonfairTryAcquire(acquires);
}
}
FairSync公平锁
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
/**当该线程前面没有其他线线程可以通过CAS去获取锁*/
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
/**如果当给钱线程以及获取了锁,对status进行累加*/
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
java中断机制
1、interrupt
interrupt 方法用于中断线程。调用该方法的线程的状态为将被置为”中断”状态。通过修改一个标志中断的布尔值
注意:线程中断仅仅是置线程的中断状态位,不会停止线程。需要用户自己去监
视线程的状态为并做处理。支持线程中断的方法(也就是线程中断后会抛出
interruptedException 的方法)就是在监视线程的中断状态,一旦线程的中断状
态被置为“中断状态”,就会抛出中断异常。
2、interrupted
线程在排队等待锁的时候如果调用了interrupted方法,就会放弃等待锁,直接抛出异常
查询当前线程的中断状态,并且清除原状态。如果一个线程被中断了,第一次调
用 interrupted 则返回 true,第二次和后面的就返回 false 了。
3、isInterrupted
仅仅是查询当前线程的中断状态