《jdk源码解析(juc)的锁-java中的锁ReetrentLock》首发橙寂博客转发请加此提示
jdk源码解析(juc)的锁-java中的锁ReetrentLock
Lock接口
Lock接口出现之前,java是通过synchronized关键字实现的锁功能,javase5之后,并发包新增了Lock接口
Lock使用方式,和分布式锁的构造很像。Lock是基于线程的,调用lock方法代表尝试获取锁,unlock代表释放锁。
Lock lock = new ReentrantLock
lock.lock();
try{
}finally{
lock.unlock();
}
Lock接口提供了Synchronized关键字不具备的特性
尝试非阻塞地获取锁 | 当前线程尝试获取锁,没有其他线程获取锁,则成功 |
---|---|
能被中断的获取锁 | |
超时获取锁 | 在指定的时间内获取锁 |
Lock接口的API
api | |
---|---|
void lock() | lock 优先考虑获取锁,待获取锁成功后,才响应中断。 |
void lockInterruptibly() throws InterruptedException | lockInterruptibly 优先考虑响应中断,而不是响应锁的普通获取或重入获取。 |
|
| boolean tryLock() | 同Lock |
| boolean tryLock(long time,TimeUtil unit) throws InterruptedException | 在一定时间time内尝试获取锁 |
| void unlock() | 释放锁 |
| Condition newCondition | 获取等待通知组件,该组件和当前的锁绑定,当前线程只有获取了锁,才能调用该组件的wait()方法,而调用后,当前线程将会释放锁 |
队列同步器AbstractQueuedSynchronized
上面介绍的是ReentrantLock中的api,最主要的事是AbstractQueuedSynchronized
在做。
锁的实现基于队列同步器完成,AbstractQueuedSynchronized(简称同步器),使用一个int成员变量state表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作
队列同步器分两种一种是NonfairSync
非公平锁默认是用非公平方式,另一种是FairSync
公平锁。
NonfairSync实现
所谓非公平,讲的是获取锁的方式不公平。排队买票,按理说先来先买,但是在这里每个新来的人都能跟你抢票。下面看源码的实现。
下面代码为我调用Lock方法时执行的一个顺序。其中有些方法不属于NonfairSync
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
//尝试着获取锁 这里也是不公平的体现,刚进来就有机会获取锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
/**
*
* 调用这个方法首先会尝试获取锁,如果获取不到会把当前线程加入等待列中
*/
public final void acquire(int var1) {
//this.acquireQueued(this.addWaiter(AbstractQueuedSynchronizer.Node.EXCLUSIVE), var1)
//这个方法把当前线程加入等待序列。具体代码自己去看。
if (!this.tryAcquire(var1) && this.acquireQueued(this.addWaiter(AbstractQueuedSynchronizer.Node.EXCLUSIVE), var1)) {
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;
}
}
FairSync实现
所谓非公平,讲的是获取锁的方式不公平。排队买票,先来先买
下面代码为我调用Lock方法时执行的一个顺序。其中有些方法不属于NonfairSync
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
*
* 调用这个方法首先会尝试获取锁,如果获取不到会把当前线程加入等待列中
*/
public final void acquire(int var1) {
//this.acquireQueued(this.addWaiter(AbstractQueuedSynchronizer.Node.EXCLUSIVE), var1)
//这个方法把当前线程加入等待序列。具体代码自己去看。
if (!this.tryAcquire(var1) && this.acquireQueued(this.addWaiter(AbstractQueuedSynchronizer.Node.EXCLUSIVE), var1)) {
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) {
//这里是跟非公平锁不一样的地方
//hasQueuedPredecessors判断线程是不是在队列中的第一个
//只有第一个才有资格去抢
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;
}
}
release方法同unLock
字面意思释放锁,unpark掉当前线程。
/**
* Releases in exclusive mode. Implemented by unblocking one or
* more threads if {@link #tryRelease} returns true.
* This method can be used to implement method {@link Lock#unlock}.
*
* @param arg the release argument. This value is conveyed to
* {@link #tryRelease} but is otherwise uninterpreted and
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
/**
* Wakes up node's successor, if one exists.
*
* @param node the node
*/
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
//从尾节点往前找,找到合适的然后干掉
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
使用案例
条件锁 Condition
Condition是针对于对象的,ReentrantLock
是针对于线程的。
部分方法描述
void await() | 当前线程进入等待状态,直到被通知或中断。 |
---|---|
void awaitUninterruptibly() | 当前线程进入等待状态,对中断不敏感 |
long awaitNanos(long nanosTimeout) | 当前线程进入等待状态,直到被通知,中断或者超时,返回值表示剩余的时间,返回值如果是0或者负数,那么可以认定已经超时了 |
boolean awaitUntil(Date deadline) | 当前线程进入等待状态,直到被通知、中断或者到某个时间,如果没有到指定时间,返回true,否则到了指定时间,返回false |
void signal() | 唤醒一个等待在condition中的线程,该线程从等待方法返回前必须获取与Condition相关联的锁 |
void signlAll() | 唤醒所有等待的condition中的线程,能够从等待方法返回的线程必须获得与condition相关联的锁 |
public class ConditionUseCase {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public static void main(String[] args){
}
public void conditionWait() throws InterruptedException {
lock.lock();
try {
condition.await();
}finally {
lock.unlock();
}
}
public void conditionSignal(){
lock.lock();
try {
condition.signal();
}finally {
lock.unlock();
}
}
}
通过Cache来解释读写锁,HashMap是非线程安全的,通过读写锁实现Cache的线程安全
public class Cache {
static Map<String,Object> map = new HashMap<String,Object>();
static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
static Lock r = rwl.readLock();
static Lock w = rwl.writeLock();
public static final Object get(String key){
r.lock();
try {
return map.get(key);
}finally {
r.unlock();
}
}
public static final Object put(String key,Object value){
w.lock();
try {
return map.put(key,value);
}finally {
w.unlock();
}
}
public static final void clear() {
w.lock();
try {
map.clear();
}finally {
w.unlock();
}
}
}
- 有界队列BoundedQueue解释Condition
public class BoundedQueue<T> {
private Object[] items;
private int addIndex,removeIndex,count;
private Lock lock = new ReentrantLock();
private Condition notEmpty = lock.newCondition();
private Condition notFull = lock.newCondition();
public BoundedQueue(int size){
items = new Object[size];
}
public void add(T t) throws InterruptedException {
lock.lock();
try {
while(count == items.length)
notFull.await();
items[addIndex] = t;
if(++addIndex == items.length)
addIndex = 0;
++count;
notEmpty.signal();
}finally {
lock.unlock();
}
}
public T remove() throws InterruptedException {
lock.lock();
try {
while(count == 0)
notEmpty.await();
Object x = items[removeIndex];
if(++removeIndex == items.length)
removeIndex = 0;
--count;
notFull.signal();
return (T) x;
}finally {
lock.unlock();
}
}
}
总结
ReentrantLock
的讲解就到此结束,看博客前希望自己看过一点源码。如果没看过的话那么请重点关注我提出来的那几个代码。如果对于这个ReentrantLock
想要更深的理解。请关注
simviso