抱歉,您的瀏覽器無法訪問本站
本頁面需要瀏覽器支持(啟用)JavaScript
了解詳情 >

java常用锁类型

常见的锁大致可以分为:乐观锁,悲观锁,排他锁,共享锁,分段锁,自选锁,公平锁,非公平锁等。。今天来学基于CAS非加锁实现的乐观锁

ReentrantLock锁

ReentrantLock类是一种可重入,公平/非公平,独占锁,它于synchronized具有相同的功能和语义,但是它更强大,它支持中断,超时等操作。Sync是ReentrantLock的内部类,他的两个子类分别代表公平锁和非公平锁,ReentrantLock可以在构造方法选择是否公平。

1
2
3
4
5
6
public void lock() {
sync.lock();
}
public void unlock() {
sync.release(1);
}

lock和unlock都是基于内部类Sync实现的,因此我们了解的重点是Sync

内部类Sync

Sync是ReentrantLock定义的一个静态内部类,他继承了AbstractQueuedSynchronizer类。它有两个实现类分别为NonfairSync(非公平锁),FairSync(公平锁),

非公平锁lock方法
1
2
3
4
5
6
7
final void lock() {
if (compareAndSetState(0, 1))//尝试获得锁
setExclusiveOwnerThread(Thread.currentThread());
else
调用AQS的acquire(int arg)方法
acquire(1);
}
公平锁lock方法
1
2
3
final void lock() {
acquire(1);//直接调用AQS的acquire(int arg)方法
}

其实无论是公平或者非公平锁的lock方法最重要的就是tryAcquire(int acquires)方法

非公平锁tryAcquire(int acquires)方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}

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;
}
公平锁tryAcquire(int acquires)方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected final boolean tryAcquire(int acquires) {
//公平锁相对于非公平锁就是多了hasQueuedPredecessors()来实现公平策略
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;
}
}
hasQueuedPredecessors()
1
2
3
4
5
6
7
8
public final boolean hasQueuedPredecessors() {

Node t = tail;//获得尾部节点
Node h = head;//获得前继节点
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}

首先头部节点不等于尾部节点则代表队列不为空———>true
s为空则代表有头节点———–>true
s不为空且s的线程不等于当前线程———>true

demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class TestReentrantLock {
private static volatile ReentrantLock lock=new ReentrantLock();
public static void main(String[] args) {
new Thread(()->{
lock.lock();
System.out.println("线程一先工作呢");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程一下班啦");
lock.unlock();
}).start();
new Thread(()->{
lock.lock();
System.out.println("线程二在工作呢");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程二下班啦");

lock.unlock();
}).start();
}
}

upload successful

Semaphore信号量

Semaphore是一种公平/非公平锁,共享锁。它可以做为一个计数器,用来保护一个或多个锁。跟上面讲解的ReentrantLock独占锁一样,核心代码都是基于类中定义的静态内部类Sync。

acquire()方法
1
2
3
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);//可以被中断的获锁方法
}

从信号量获取一个许可,如果无可用许可前将一直阻塞等待。

acquireSharedInterruptibly(int arg)方法
1
2
3
4
5
6
7
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())//如果当前线程被中断就抛出异常
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)//尝试获得异常
doAcquireSharedInterruptibly(arg);//获锁失败放进等待队列
}
tryAcquireShared(int arg)方法
非公平锁实现
1
2
3
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
1
2
3
4
5
6
7
8
9
10
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();//获得可用锁数量
int remaining = available - acquires;
//如果没有锁了就直接返回否则尝试获得锁资源
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
公平锁实现
1
2
3
4
5
6
7
8
9
10
11
protected int tryAcquireShared(int acquires) {
for (;;) {
if (hasQueuedPredecessors())//公平策略就是判断当前节点是否有前驱节点(跟上面的ReentrantLock的公平策略一样的)
return -1;
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
doAcquireSharedInterruptibly(int arg)

分析请见

release(int arg)方法

1
2
3
public void release() {
sync.releaseShared(1);
}

释放信号量中的一个许可,如果多次调用会扩大信号量的可用数量。

releaseShared(int arg)方法
1
2
3
4
5
6
7
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg))//尝试释放锁 {
doReleaseShared();
return true;
}
return false;
}
tryReleaseShared(int releases)方法
1
2
3
4
5
6
7
8
9
10
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();//获得队列中可用锁数量
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))//尝试设置数量
return true;
}
}
doReleaseShared()方法

分析请见