Java并发编程——synchronize 和 ReentrantLock
1.synchronize
2.ReentrantLock
显式锁ReentrantLock
与 内置锁synchronize
不同,它并不是一种替代内置锁的方式,而是作为一种可选择的高级功能。
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
ReentrantLock 实现了 Lock接口,意味着其具有无条件的,可中断的,可轮询以及定时的锁获取操作,所有的加锁与解锁必须显式的调用!
2.1 公平锁与非公平锁
我们先来讨论以下ReentrantLock高级功能之一:公平锁与非公平锁!
ReentrantLock 默认采用非公平锁
public ReentrantLock() {
sync = new NonfairSync(); //此处默认是非公平锁!
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
再看看公平锁和非公平锁的实现,两者都是实现了Sync的静态内部类。先看下公平锁的核心方法:
/**
* Sync object for fair locks
*/
//公平锁!!!!!!!
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
//注意这个acquire方法是在AbstractQueuedSynchronizer中实现的!并不是公平锁的方法!
public final void acquire(int arg) {
if (!tryAcquire(arg) && //当前线程是否能获得锁!
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//获取不了加入到等待队列的尾部
selfInterrupt(); //最终阻塞当前线程!
}
/**
* 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(); //获取锁计数信息
if (c == 0) { //判断是否为0,即当前是否有线程正持有这个锁!
if (!hasQueuedPredecessors() && //首先会判断是否有线程正在等待,如果有等待,为保证公平性跳到最底部返回false,即试图获取锁失败!
compareAndSetState(0, acquires)) { //然后通过cas操作竞争锁
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //ok,有线程持有这个锁,就判断一下是否是本线程持有这个锁,ok,持有,重入!
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc); //更改锁计数信息
return true;
}
return false; // 都不是,直接返回false
}
}
再看下非公平锁的
static final class NonfairSync extends Sync {
final void lock() {
// 和公平锁相比,这里会直接先进行一次CAS,成功就返回了
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
// AbstractQueuedSynchronizer.acquire(int arg)
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
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) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
总结
- 非公平锁在调用 lock 后,首先就会调用 CAS 进行一次抢锁,如果这个时候恰巧锁没有被占用,那么直接就获取到锁返回了。
- 非公平锁在 CAS 失败后,和公平锁一样都会进入到 tryAcquire 方法,在 tryAcquire 方法中,如果发现锁这个时候被释放了(state == 0),非公平锁会直接 CAS 抢锁,但是公平锁会判断等待队列是否有线程处于等待状态,如果有则不去抢锁,乖乖排到后面。
本作品采用《CC 协议》,转载必须注明作者和本文链接