10.AQS抽象队列同步器

  1. 同步锁的本质-排队
  • 同步的方式:独享锁-单个队列窗口,共享锁-多个队列窗口
  • 抢锁的方式:插队锁(不公平锁)、先来后到抢锁(公平锁)
  • 没抢到锁的处理方式:快速尝试多次(CAS自旋锁)、阻塞等待
    唤醒阻塞线程的方式(叫号器):全部通知、通知下一个
  1. 区别
  • lock:synchronized是一种悲观锁,每次都把自己关起来做事,怕被抢而lock底层是CAS乐观锁的体现,无所谓外界,如果被抢了,就重新去拿,很乐观,底层主要靠volatile和CAS实现的
  • synchronized:可以保证方法或者代码块在运行时同一时刻只有一个线程能进入临界区,同时保证共享变量对其他线程的可见性
  • JDK1.6之前Synchronized是一个重量级锁,是通过对象内部的一个叫做监视器锁(monitor)来实现的,但是监视器本质又是依赖于底层的操作系统的Mutex Lock来实现的,而操作系统实现线程之间的切换这就需要从用户态转换到核心态,性能低。但是从1.7之后jvm做了很多优化,性能上面差别Lock不多,一般情况下推荐使用synchronized
  1. 自定义锁实现
//只是基本demo,还有很多未完善
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;

public class TonyLock implements Lock {
    //判断一个所得状态或者说拥有者
    volatile AtomicReference owner = new AtomicReference<>();
    //保存正在等待的队列
    volatile LinkedBlockingQueue waiters = new LinkedBlockingQueue<>();


    @Override
    public boolean tryLock() {
        return owner.compareAndSet(null, Thread.currentThread());
    }

    @Override
    public void lock() {
        boolean flag = true;
        while (!tryLock()) {
            if (flag) {
                waiters.add(Thread.currentThread());
                flag = false;
            }else{
                LockSupport.park();//while循环,避免伪唤醒
            }
        }
        waiters.remove(Thread.currentThread());
    }

    @Override
    public void unlock() {
        //如果现有存储线程和当前线程是同一个就用null释放,
        if (owner.compareAndSet(Thread.currentThread(),null)) {//释放成功
            Iterator iterator=waiters.iterator();
            while (iterator.hasNext()) {
                LockSupport.unpark(iterator.next());
            }

        }
    }
    @Override
    public void lockInterruptibly() throws InterruptedException {}
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }
    @Override
    public Condition newCondition() {
        return null;
    }
}
  1. AQS抽象队列同步器
    提供了对资源占用、释放、线程的等待、唤醒等等接口和具体实现。可以用在各种需要控制资源争用的场景中。(ReentrantLock/CountDownLatch/Semphore)


    1.png
  • 资源占用流程


    2.png
//模拟实现简化版aqs以及使用aqs:官方提供aqs其实也是这样的思路
public class TonyAQS {
    //判断一个所得状态或者说拥有者
    volatile AtomicReference owner = new AtomicReference<>();
    //保存正在等待的队列
    volatile LinkedBlockingQueue waiters = new LinkedBlockingQueue<>();
    volatile AtomicInteger state=new AtomicInteger(0);

    //交给使用者去实现,如果不实现,默认会抛异常
    public boolean tryAcquire() {
        throw new UnsupportedOperationException();
    }

    public void acquire() {
        boolean flag = true;
        while (!tryAcquire()) {
            if (flag) {
                waiters.add(Thread.currentThread());
                flag = false;
            }else{
                LockSupport.park();//while循环,避免伪唤醒
            }
        }
        waiters.remove(Thread.currentThread());
    }

    public boolean tryRelease() {
        throw new UnsupportedOperationException();
    }

    public void release() {
        if (tryRelease()) {
            Iterator iterator=waiters.iterator();
            while (iterator.hasNext()) {
                LockSupport.unpark(iterator.next());
            }

        }
    }
}


//使用
public class TonyLock implements Lock {

    TonyAQS tonyAQS=new TonyAQS(){
        @Override
        public boolean tryAcquire() {
            return owner.compareAndSet(null, Thread.currentThread());
        }

        @Override
        public boolean tryRelease() {
            //如果是可重入的情况下,要判断资源的占用情况(就是前面一个类未使用的state字段,state字段保存了资源的占用次数,只有次数为0才能进入该释放)
            return owner.compareAndSet(Thread.currentThread(),null);
        }
    };

    @Override
    public boolean tryLock() {
        return tonyAQS.tryAcquire();
    }

    @Override
    public void lock() {
        tonyAQS.acquire();
    }

    @Override
    public void unlock() {
        tonyAQS.release();
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }


    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }


    @Override
    public Condition newCondition() {
        return null;
    }
}
  1. 公平锁和非公平锁的区别
  • 公平锁:顾名思义–公平,大家老老实实排队。
  • 非公平锁:只要有机会就尝试抢占资源
  • 非公平锁的弊端:可能导致后面排队等待的线程等不到相应的CPU资源,从而引起线程饥饿。

你可能感兴趣的:(10.AQS抽象队列同步器)