微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JUC-AQS

1 概述

队列同步器,全称是 AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的基础框架

特点:

  • 用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁
    • getState - 获取 state 状态
    • setState - 设置 state 状态
    • compareAndSetState - 乐观锁机制设置 state 状态
    • 独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源
  • 提供了FIFO的等待队列,类似于 Monitor 的EntryList
  • 条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的WaitSet

子类主要实现这样一些方法认抛出 UnsupportedOperationException)

方法名称 描述
tryAcquire 独占锁获取同步状态,实现该方法需要查询当前状态并判断同步状态是否符合预期,然后再进行CAS设置同步状态
tryRelease 独占式释放同步状态,等待获取同步状态的线程将有机会获取同步状态
tryAcquireShared 共享式获取同步状态,返回大于等于0的值,表示获取成功,反之,获取失败
tryRelease 共享式释放同步状态
isHeldExclusively 当前同步器是否在独占模式下被线程占用,一般该方法表示是否被当前线程所独占

获取锁的姿势

//如果获取锁失败
if(!tryAcquire(arg)){
	//入队,可以选择阻塞当前线程 park unpark
}

释放锁的姿势

if(tryRelease(arg)){
	//让阻塞线程恢复运行
}

2 实现不可重入锁

2.1 自定义同步器

//独占锁  同步器类
    class MySync extends AbstractQueuedSynchronizer{
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0,1)){
                //加上了锁,并设置 owner 为当前线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        @Override
        //是否持有独占锁
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        public Condition newCondition(){
            return new ConditionObject();
        }
    }

2.2 自定义

class MyLock implements Lock{

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

2.3 测试

public static void main(String[] args) {
        MyLock lock = new MyLock();
        new Thread(() -> {
            lock.lock();
            try{
                System.out.println("["+Thread.currentThread().getName()+"]"+"locking....");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printstacktrace();
            } finally {
                System.out.println("["+Thread.currentThread().getName()+"]"+"unlocking....");
                lock.unlock();
            }
        },"t1").start();

        new Thread(() -> {
            lock.lock();
            try{
                System.out.println("["+Thread.currentThread().getName()+"]"+"locking....");
            }finally {
                System.out.println("["+Thread.currentThread().getName()+"]"+"unlocking....");
                lock.unlock();
            }
        },"t2").start();
    }
22:29:28.727 c.TestAqs [t1] - locking... 
22:29:29.732 c.TestAqs [t1] - unlocking... 
22:29:29.732 c.TestAqs [t2] - locking... 
22:29:29.732 c.TestAqs [t2] - unlocking...

不可重入测试

如果改为下面代码,会发现自己也会被挡住(只会打印一次 locking)

lock.lock();
log.debug("locking...");
lock.lock();
log.debug("locking...");

原文地址:https://www.jb51.cc/wenti/3281081.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐