实现AQS


java.util.concurrent包结构
在这里插入图片描述
其中包含了两个子包:automic和lock,阻塞队列,executors这些都是juc中的精华。这些类的实现主要依赖于volatile以及CAS
在这里插入图片描述

lock简介

锁是用来控制多个线程访问共享资源的方式,java SE5都是靠synchronized实现锁功能的,它拥有很多优点,比如锁获取和释放的可操作性,可中断的获取锁,超时获取锁等其他同步特性
转移:synchronized同步块执行完成或者遇到异常时,锁是会自动释放的,但是lock必须显示释放锁

lock的简单使用

Lock lock=new RentrantLock();
lock.lock();
try{
    ....
}finally{
 lock.unlock();
}

trylock的简单使用

尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false

Lock lock=new RentrantLock();
     if (lock.tryLock()) {
        try {
          // manipulate protected state
        } finally {
          lock.unlock();
        }
     } else {
        // perform alternative actions
     }}

lock定义的方法

  • void lock(); //获取锁,就是获取资源
  • void unlock(); //释放锁,释放资源给其他线程用
  • void lockInterruptibly(); // 可响应中断的获取锁
  • boolean tryLock(); //非阻塞式的获取锁
  • boolean tryLock(long time, TimeUnit unit) // 在超时时间内或者未中断的情况下获取锁
  • Condition newCondition(); //获取与lock锁绑定的等待通知组件

ReentrantLock的实现

基本上所有的方法都是调用了其静态内部类的Sync的方法,而Sunc继承了AbstractQueuedSunchronizer(AQS)

AQS简介

同步器是用来构建锁和其他同步组件的基础框架,它依赖同步状态和一个同步队列,子类必须重写AQS的几个改变状态的方法,其他方法主要实现了排队和阻塞机制

  1. 锁是面向使用者,定义了使用者与锁交互的接口
  2. 同步器面向锁的实现者,简化了锁得实现方式,屏蔽了同步状态的管理线程的排队等待和唤醒等底层操作。

AQS使用模板方法实现设计模式

模板方法:同步器将一些方法开放给子类重写,而同步器提供的模板方法又会重新调用子类重写的方法
AQS需要重写的方法

protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
}

ReentrantLock重写

protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

AQS中的模板方法acquire()

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
 }

重写AQS经验总结

  • 同步组件的实现依赖同步器,使用AQS的方式被推介定义 继承AQS的静态内部类
  • AQS采用模板方法设计,AQS的protected方法需要子类重写,当调用模板方法时就可以调用被重写方法
  • AQS负责同步状态的管理,线程的排队,等待唤醒等底层操作,而自定义同步组件主要专注于 实现同步语义
  • 重写AQS时,使用AQS提供的getState().setState(),compareAndSetState()修改同步状态

AQS可重写的方法

  • boolean tryAcquire(int arg)
    独占式的获取同步状态,需要查询当前状态并判断是否符合预期,然后再通过CAS设置同步状态
  • boolean tryRelease(int arg) 独占式的释放同步状态
    ————————————————————————————————
  • int tryAcquireShared(int arg) 共享式的获取同步状态,返回>=0表示获取成功
  • boolean tryReleaseShared(int arg)共享式的释放同步状态
  • boolean isHeldExclusively() 当前同步器是否被当前线程所独占

实现同步组件时AQS提供的模板方法

  1. 独占式获取与释放同步状态
  2. 共享式获取与释放同步状态
  3. 查询同步队列中等待线程的情况
  • void acquire(int arg) 独占式的获取同步状态,若当前线程获取同步状态成功则返回,否则将进入同步队列等待
  • boolean release(int arg) 独占式的释放同步状态,释放同步状态后,将同步队列中第一个节点包含的线程唤醒
    ———————————————————————————————————
  • void acquireShared(int arg) 共享式的获取同步状态,同一时刻会有多个线程获取到同步状态
  • boolean release(int arg) 共享式的释放同步状态
    ———————————————————————————————————
  • void acquireInterruptibly(int arg) 若当前线程被中断,则抛出异常
  • void acquireSharedInterruptibly(int arg) 若当前线程被中断,则抛出异常

实现一个同步组件

class Mutex implements Lock, java.io.Serializable {
    // Our internal helper class
    // 继承AQS的静态内存类
    // 重写方法
    private static class Sync extends AbstractQueuedSynchronizer {
        // Reports whether in locked state
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
    // Acquires the lock if state is zero
    public boolean tryAcquire(int acquires) {
        assert acquires == 1; // Otherwise unused
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    // Releases the lock by setting state to zero
    protected boolean tryRelease(int releases) {
        assert releases == 1; // Otherwise unused
        if (getState() == 0) throw new IllegalMonitorStateException();
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
    }

    // Provides a Condition
    Condition newCondition() {
        return new ConditionObject();
    }

    // Deserializes properly
    private void readObject(ObjectInputStream s)
            throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
    }
}

// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
//使用同步器的模板方法实现自己的同步语义
public void lock() {
    sync.acquire(1);
}

public boolean tryLock() {
    return sync.tryAcquire(1);
}

public void unlock() {
    sync.release(1);
}

public Condition newCondition() {
    return sync.newCondition();
}

public boolean isLocked() {
    return sync.isHeldExclusively();
}

public boolean hasQueuedThreads() {
    return sync.hasQueuedThreads();
}

public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}

public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

同步组件实现者角度:告诉AQS怎么判断当前同步状态是否成功获取or成功释放
AQS角度:需要同步组件返回true和false,然后对不同的结果做不同处理

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值