一、自己先实现一个锁
思路:使用CAS原子操作实现线程安全+使用阻塞队列实现排队等待
上代码:
public class MyLock implements Lock {
volatile AtomicReference<Thread> flag = new AtomicReference<Thread>();// 锁标志位
volatile LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<Thread>();// 存放等待线程
@Override
public boolean tryLock() {
// 使用CAS原子操作加锁
return flag.compareAndSet(null, Thread.currentThread());
}
@Override
public void lock() {
boolean in = true;// 放置多次入队
while (!tryLock()) {
if (in) {// 没拿到锁则进入队列等待
waiters.offer(Thread.currentThread());
in = false;
LockSupport.park();// 当前线程挂起,阻塞执行
}
}
waiters.remove(Thread.currentThread());// 拿到锁则从等待队列中移除
}
@Override
public void unlock() {
if (flag.compareAndSet(Thread.currentThread(), null)) {// 重置标志位为null
Iterator<Thread> it = waiters.iterator();
while (it.hasNext()) {
LockSupport.unpark(it.next());
}
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
// TODO Auto-generated method stub
}
@Override
public Condition newCondition() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
// TODO Auto-generated method stub
return false;
}
}
test:
public class LockTest4 {
private static final Lock lock = new MyLock();
public static void main(String[] args) {
LockTest4 lt = new LockTest4();
new Thread(new Runnable() {
@Override
public void run() {
lt.mm();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
lt.mm();
}
}).start();
}
private static void mm() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "开始执行...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "执行结束...");
} finally {
lock.unlock();
}
}
}
输出结果:
Thread-0开始执行…
Thread-0执行结束…
Thread-1开始执行…
Thread-1执行结束…
二、jdk中的锁实现
我们进入到ReentrantLock的几个方法实现:
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
看到这里,是否会惊讶到,这么简洁么!但sync是个什么鬼?
我们继续跟踪:
/** Synchronizer providing all implementation mechanics */
//同步器提供所有实施机制
private final Sync sync;
/**
* Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
这里翻译过来就是ReentrantLock内部实现了一个静态内部类-同步控制器实现类,而它是继承于最高级封装的AbstractQueuedSynchronizer抽象队列同步器实现的,且后续有公平和非公平两个版本(NonfairSync ,FairSync),AQS state用于持有锁计数,这个是指重入锁。
ReentrantLock支持公平锁与非公平锁,默认是非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
- 公平锁
final void lock() {
acquire(1);
}
这里调用了AQS的阻塞式获取锁资源
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
- 非公平锁
final void lock() {
if (compareAndSetState(0, 1))//首先就会直接尝试CAS获取锁,插队
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
三、AQS封装及使用
1、两种方式
独享操作 | 共享操作 | 描述 |
---|---|---|
acquire | acquireShared | 获取锁资源,没拿到则等待,由AQS实现 |
release | releaseShared | 释放所资源,由AQS实现 |
tryAcquire | tryAcquireShared | 执行占用资源的操作,由使用者实现 |
tryRelease | tryReleaseShared | 执行释放资源的操作,由使用者实现 |
2、一个标志位
/**
* The synchronization state.
*/
private volatile int state;
这个state状态作用有三:
- 标识锁是否被持有,默认为0
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
- 用于重入锁计数,每lock一次就会+1,相对释放锁就是恢复的过程
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;
}
- 用于Semaphore信号量限流
3、一个链表
AQS中自己维护了一个双向链表结构来实现线程队列等待。
static final class Node {
//表示共享模式(共享锁)
static final Node SHARED = new Node();
//表示独占模式(独占锁)
static final Node EXCLUSIVE = null;
//表示线程已取消
static final int CANCELLED = 1;
//表示当前结点的后继节点需要被唤醒
static final int SIGNAL = -1;
//线程(处在Condition休眠状态)在等待Condition唤醒
static final int CONDITION = -2;
/表示锁的下一次获取可以无条件传播,在共享模式头结点有可能处于这种状态
static final int PROPAGATE = -3;
//线程等待状态
volatile int waitStatus;
//前继节点
volatile Node prev;
//后继节点
volatile Node next;
//当前节点所代表的的线程
volatile Thread thread;
//可以理解为当前是独占模式还是共享模式
Node nextWaiter;
//如果节点在共享模式下等待,则返回true
final boolean isShared() {
return nextWaiter == SHARED;
}
//获取前一个节点
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
//三个构造方法分别用于不同场景
Node() {
}
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) {
this.waitStatus = waitStatus;
this.thread = thread;
}
}
- 入队
如果当前线程通过CAS获取锁失败,则会将该线程信息封装为一个节点,追加到队列末尾。
//获取锁资源
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//包装当前线程,添加到队列中
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;
}
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
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 (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//通过park/unpark机制
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
- 出队
//释放锁资源
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//唤醒并出队
unparkSuccessor(h);
return true;
}
return false;
}
4、自己实现一个AQS
基于我们开始实现的锁,我们也抽象封装成自己的简单AQS同步器来使用:
这里只实现了独享锁,偷懒使用了现成的队列…
public class MyAQS {
public volatile AtomicReference<Thread> flag = new AtomicReference<Thread>();// 锁标志位
volatile LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<Thread>();// 存放等待线程
public boolean tryAcquire() {// 需要使用者自己实现
throw new UnsupportedOperationException();
}
public void acquire() {
boolean in = true;// 放置多次入队
while (!tryAcquire()) {
if (in) {// 没拿到锁则进入队列等待
waiters.offer(Thread.currentThread());
in = false;
LockSupport.park();// 当前线程挂起,阻塞执行
}
}
waiters.remove(Thread.currentThread());// 拿到锁则从等待队列中移除
}
public boolean tryRelease() {
throw new UnsupportedOperationException();
}
public void release() {// 释放锁资源操作交给子类,这里定义了释放资源后的操作
if (tryRelease()) {
Iterator<Thread> it = waiters.iterator();
while (it.hasNext()) {
LockSupport.unpark(it.next());
}
}
}
}
public class MyLock implements Lock {
MyAQS aqs = new MyAQS() {
@Override
public boolean tryAcquire() {
return flag.compareAndSet(null, Thread.currentThread());
}
@Override
public boolean tryRelease() {
return flag.compareAndSet(Thread.currentThread(), null);
}
};
@Override
public boolean tryLock() {
// 使用CAS原子操作加锁
return aqs.tryAcquire();
}
@Override
public void lock() {
aqs.acquire();
}
@Override
public void unlock() {
aqs.release();
}
@Override
public void lockInterruptibly() throws InterruptedException {
// TODO Auto-generated method stub
}
@Override
public Condition newCondition() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
// TODO Auto-generated method stub
return false;
}
}