AQS
有如下代码
import sun.nio.ch.ThreadPool;
import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
public class Solution{
static int val=0;
static ReentrantLock lock=new ReentrantLock();
public static void main(String[] args) {
Thread t1=new Thread(()->count());
Thread t2=new Thread(()->count());
Thread t3=new Thread(()->count());
t1.start();
t2.start();
t3.start();
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(val);
}
static void count(){
try {
lock.lock();
for(int j=0;j<10000;j++){
val++;
}
} finally {
lock.unlock();
}
}
}
执行结果
30000
程序=思想+代码
解决问题的思路
银行办业务
1、看办理的人多不多,不多就直接去柜台,多就排队
2、等待区
3、如果行长小舅子来办业务,不需要排队,柜台空了就直接去办
(非公平)
4、过号了,重排
过号了,重排的代码
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
六个操作
state
默认是0,没有线程占有锁
改成了1,有线程占有了锁
抢锁
1、看锁标志位,默认是0,所以这时候有线程抢到锁
需要改锁标志位
需要一种机制
CAS机制
2、有线程占有了锁,这时候有线程来抢锁
1、当前来抢锁的线程是不是占有锁的线程
是 重入 state+1
为什么要记录次数
因为释放的时候需要释放对应的次数
2、如果不是,抢锁失败
3、优化∶看等待区有没有人,如果有人,锁肯定被占用了
如何判断有人在等待
hasQueuedPredecessors
公平锁、非公平锁存在差异的地方唯一的差别就是一个临界区
公平锁
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;
}
非公平锁
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;
}
释放锁
1、重入问题
2、锁状态为恢复为0
3、唤醒队列中等待的线程
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
特殊情况
唤醒失败
队列的中部出队
入队
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
出队
出队这个事情谁来做?
被唤醒的线程来做的
阻塞
LockSupport.park(this);
唤醒
LockSupport.unpark