您好,登錄后才能下訂單哦!
1、啟動文件
public class Main {
public static void main(String[] args) throws ParseException {
ReentrantLock lock = new ReentrantLock(true);
Thread t1 = new Thread(new Task(lock),"Thread-1");
Thread t2 = new Thread(new Task(lock),"Thread-2");
Thread t3 = new Thread(new Task(lock),"Thread-3");
t1.start();
t2.start();
t3.start();
}
}
2、Task
import java.util.concurrent.locks.ReentrantLock;
public class Task implements Runnable{
private ReentrantLock lock;
public Task(ReentrantLock lock) {
this.lock = lock;
}
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "獲取到鎖....");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + "釋放鎖....");
lock.unlock();
}
}
}
3、執(zhí)行結果:
protected final boolean tryAcquire(int acquires) { //參數是1
final Thread current = Thread.currentThread(); //當前線程
int c = getState(); //獲取當前同步狀態(tài)
if (c == 0) { //如果是0,則鎖沒有被占用
//等待隊列中,前面沒有其他等待的線程,則用CAS的方法更新同步狀態(tài)state
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current); //成功的話,則設置鎖的占有線程為當前線程
return true; //返回獲取資源成功
}
}
//如果鎖已經被占用,則判斷是不是自己占用的
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;//如果是自己占用的,則是重入,增加state值,累加1
if (nextc < 0) //重入次數過大,拋出異常
throw new Error("Maximum lock count exceeded");
setState(nextc); //設置state值
return true; //重入返回ture
}
return false;//沒有獲取資源返回false
}
private Node addWaiter(Node mode) {
//把當前線程包裝成節(jié)點,準備放入等待隊列
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
//嘗試直接把節(jié)點設置成隊尾,否則執(zhí)行enq
Node pred = tail;
if (pred != null) {
node.prev = pred;//當前節(jié)點的上一個節(jié)點是之前的隊尾節(jié)點
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//當前節(jié)點插入隊尾
enq(node);
return node;
}
private Node enq(final Node node) {
//采用自旋,保證節(jié)點插入
for (;;) {
Node t = tail;
if (t == null) { // Must initialize 如果隊列為空,則創(chuàng)建一個空的節(jié)點,設置為頭尾節(jié)點
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) { //隊列不為空,追加到隊尾
t.next = node;
return t;
}
}
}
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//判斷節(jié)點的前任節(jié)點是不是頭節(jié)點,頭節(jié)點是一個空節(jié)點
final Node p = node.predecessor();
//如果是頭節(jié)點,則說明當前節(jié)點是隊列里的第一個節(jié)點,首節(jié)點。
//則嘗試獲取鎖資源,此處因為Thread-1占用著資源,則失敗
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//失敗之后,則判斷當前節(jié)點線程Thread-2是不是可以阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;//前驅節(jié)點的狀態(tài)
if (ws == Node.SIGNAL) //如果是SIGNAL,則說明前驅節(jié)點狀態(tài)可以喚醒后繼節(jié)點,可以阻塞
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev; //只有CANCELLED狀態(tài)大于0,則把取消狀態(tài)的節(jié)點從隊列刪除
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//設置前驅節(jié)點為SIGNAL狀態(tài)
}
return false;
}
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。