3.1.1 重入锁 以及源码分析

package 第三章.重入锁;

import java.util.concurrent.locks.ReentrantLock;

/**
* Created by zzq on 2018/1/22.
*/
public class ReentrantLockTest implements Runnable{
public static ReentrantLock lock=new ReentrantLock(true);
public static int a=0;
public void run() {
for (int i = 0; i < 1000000; i++) {
lock.lock();
try{
a++;
}finally {
lock.unlock();
}
}
}

public static void main(String[] args) throws InterruptedException {
ReentrantLockTest reentrantLockTest=new ReentrantLockTest();
Thread thread1=new Thread(reentrantLockTest);
Thread thread2=new Thread(reentrantLockTest);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(a);
}
}


一。构造函数:

ReentrantLock有两种类型的锁,公平锁和非公平锁,默认的是非公平锁。(如果设置为公平锁,那么就会根据执行的顺序,阻塞)

1.默认情况 public ReentrantLock() {
sync = new NonfairSync();
}

2.传入参数 true则为公平锁 public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

二。lock方法解读:


(非公平锁的lock方法) final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
unsafe的compareAndSwapInt方法是native的.
compareAndSetState(0, 1) 尝试获取锁,把state的状态从0改为1表示获取锁,setExclusiveOwnerThread这个方法是设置获取锁的线程为当前线程。

如果获取所失败,acquire(1)

public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}


protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}

final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); //获取当前state的值
if (c == 0) { //如果当前的值为0,也就是说有获取锁的线程释放了锁,然后类似lock方法获取锁
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //如果当前线程就是获取锁的线程,那么state+1
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}


--------------------
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 创建一个node 添加到Node中 有volatile修饰可见
然后遍历Node

final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} catch (RuntimeException ex) {
cancelAcquire(node);
throw ex;
}
}

acquireQueued也是个无限循环.就是说要么获取到锁,要么中断当前线程.
acquireQueued会再次调用tryAcquire,就是再尝试一次获取锁.
shouldParkAfterFailedAcquire是判断是否要中断当前线程.


private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}

2.unlock方法:

public void unlock() {
sync.release(1);
}

public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}


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;
}

从tryRelease可以看到释放锁的条件是:c == 0 就是锁的计数为0;
unparkSuccessor:释放锁.

private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);

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);
}




posted @ 2018-02-07 10:41  anxbb  阅读(197)  评论(0编辑  收藏  举报