AQS基本

park和unpark

LockSupport.park();// 暂停当前线程
LockSupport.unpark(暂停线程对象);// 恢复某个线程的运行

unpark也可以在park之前调用,调用之后,对应的线程中如果后面执行了park,并不会停止
// 原理
每个线程都会关联一个Parker对象,Parker对象由三部分组成(_counter,_cond,_mutex)
调用park时:
_counter为0:则就进入_cond休息,将_counter再次置为0,线程停止运行
_counter为1,不需要休息,将_counter置为0,继续运行
调用unpark时:
线程在_cond中休息,将_counter变为1,将线程唤醒,线程将_counter变为0,继续向下运行
线程在运行,将_counter变为1,线程照常继续运行
Thread t1 = new Thread(() -> {
    log.debug("park...");
    LockSupport.park();// 让当前线程停下来
    log.debug("unpark...");
    log.debug("打断状态: {}", Thread.currentThread().isInterrupted());

    // 打断标记为真时,park无效,会继续向下运行
    LockSupport.park();
    log.debug("unpark...");
});
t1.start();

TimeUnit.SECONDS.sleep(1);
t1.interrupt();// 让park的线程恢复运行

AQS原理

ReentrantLock
CountDownLatch
ReentrantReadWriteLock
Semaphore
等都是基于AQS的

# AbstractQueuedSynchronizer.java
# 提供了一个模板用于实现(依赖于FIFO等待队列的阻塞锁和一些同步器)
# AQS解决了实现一个synchronizer的大量细节
# Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that 
# rely on first-in-first-out (FIFO) wait queues.  

state属性表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁
独占模式:只能有一个线程访问资源
共享模式:可以有多个线程访问资源

AQS的实现依赖内部的双向队列,如果当前线程竞争锁失败,AQS会把当前线程以及等待状态信息封装成一个Node加入到同步队列中
同时再阻塞该线程,当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点(线程)

等待队列是"CLH"锁队列的一种变体
# The wait queue is a variant of a "CLH" lock queue.  
CLH锁通常用于自旋锁
# CLH locks are normally used for spinlocks.
相反,我们将它们用于阻塞同步器,但是使用相同的基本策略,将关于线程的一些控制信息保存在其节点的前任中
# We instead use them for blocking synchronizers, but use the same basic tactic of holding
# some of the control information about a thread in the predecessor of its node.
// 实现一个独占锁,需要子类实现
protected boolean tryAcquire(int arg) // state改为1,true表示加锁成功,将当前线程置为Owner线程
protected boolean tryRelease(int arg) // state改为0,Owner线程置为null
protected boolean isHeldExclusively()

// AQS中的acquire方法是加独占锁,内部会调用tryAcquire
// This method can be used to implement method {@link Lock#lock}.
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
// AQS中的release方法是释放独占锁,内部会调用tryRelease
// This method can be used to implement method {@link Lock#unlock}.
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h); // 唤醒等待队列中线程
        return true;
    }
    return false;
}

自定义的不可重入独占锁

@Slf4j
public class Singleton{
    public static void main(String[] args) {
        MyLock lock = new MyLock();
        new Thread(() -> {
            lock.lock();
            try {
                log.debug("lock...");
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                log.debug("unlock...");
                lock.unlock();
            }
        },"t1").start();
        new Thread(() -> {
            lock.lock();
            try {
                log.debug("lock...");
            } finally {
                log.debug("unlock...");
                lock.unlock();
            }
        },"t2").start();
    }
}
final class MySync extends AbstractQueuedSynchronizer {
    @Override// 尝试获取锁
    protected boolean tryAcquire(int acquires) {
        if (acquires == 1){
            if (compareAndSetState(0, 1)) {// 将state置为1(原子性)
                setExclusiveOwnerThread(Thread.currentThread());// 将当前线程设置为owner线程
                return true;
            }
        }
        return false;
    }
    @Override// 尝试释放锁
    protected boolean tryRelease(int acquires) {
        if(acquires == 1) {
            if(getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        return false;
    }
    protected Condition newCondition() {
        return new ConditionObject();
    }
    @Override// 是否持有锁
    protected boolean isHeldExclusively() {
        return getState() == 1;
    }
}
class MyLock implements Lock {
    static MySync sync = new MySync();
    @Override// 加锁,不成功就等待
    public void lock() {
        sync.acquire(1);
    }
    @Override // 加锁,不成功就等待可打断
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    @Override// 尝试加锁,失败不进入等待队列
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }
    @Override// 释放锁
    public void unlock() {
        sync.release(1);
    }
    @Override// 生成条件变量
    public Condition newCondition() {
        return sync.newCondition();
    }
}
// tryAcquireShared
尝试获取资源.负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源
//tryReleaseShared
尝试释放资源,成功则返回true,失败则返回 false

AQS详解
太难了,以后慢慢看吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值