目录
- 多线程例子程序:两个线程累加共享变量,结果正确
- 非公平锁加锁(即` lock.lock();`)过程
- 非公平锁解锁(` lock.unlock();`)过程
- 公平锁
- 公平锁的加锁逻辑
- 公平锁的释放锁逻辑
多线程例子程序:两个线程累加共享变量,结果正确
public class Test {
static int count = 0;
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run () {
try {
lock.lock();
for (int i = 0; i < 10000; i++) {
count++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
非公平锁加锁(即 lock.lock();
)过程
- ReentrantLock的lock方法 走到 同步器的 acquire(1)方法
- 走到aqs的acquire的方法,而其tryAcquire方法实现则是在NonfairSync类中
- NonfairSync执行tryAcquire方法又回到Sync的nonfairTryAcquire方法
- Sync的nonfairTryAcquire方法则如下
相关代码 java.util.concurrent.locks.ReentrantLock.Sync#nonfairTryAcquire
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
@ReservedStackAccess
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;
}
- 进行cas自旋获取,成功则设置当前线程获取到锁(此时state=1),否则一直自旋。
- 如果当前线程就是获取到锁的线程,则为可重入,此时 state > 1
- 其中
private volatile int state;
volatile保证可见性、有序性,不保证原子性(CAS
操作保证原子性)
可以看到
- 当一个线程lock获取到锁后成功返回,并执行自己的代码
- 其它线程获取不到锁,则一直自旋在哪里
非公平锁解锁( lock.unlock();
)过程
释放锁则相对简单,如下图所示
相关代码java.util.concurrent.locks.ReentrantLock.Sync#tryRelease
@ReservedStackAccess
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;
}
公平锁
从上面非公平锁可以看到,加锁操作时看哪个线程cas抢到就行,至于谁抢到无所谓。可能有线程永远抢不到,即线程饥饿。这就出现了不公平的现象了
当new ReentrantLock(true);
就得到了一个公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
公平锁的加锁逻辑
体现在java.util.concurrent.locks.ReentrantLock.FairSync#tryAcquire
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;
}
-
会先判断当前线程前面是否有等待的线程,即利用asq的等待队列进行判断
- 如果有,则自己加入到链表尾部;返回false
- 如果队列为空或者自己就是链表头;返回true
-
hasQueuedPredecessors返回false,则可以进行cas获取锁操作了
-
hasQueuedPredecessors返回true,那么自己则要排队了,先来后到(公平),不用cas操作了,直接加锁失败
公平锁的释放锁逻辑
同非公平锁