juc aqs 原理

一.背景

     并发包中的各种并发工具基础都是用了AQS(AbstractQueuedSynchronizer),这个工具和Synchronizer关键字提供的功能类似,但是比Synchronizer要更好用

     有如下改进:

     1.获取锁时,AQS时能响应中断(阻塞线程被唤醒后会检查中断标志位,来响应中断);Synchronized不会响应中断(线程阻塞在Synchronized时(这是java线程状态是"Blocked"),不会响应中断(被唤醒后,不会检查线程中断标志位))。

     2.获取锁时,AQS可以超时时间,超时后返回失败,不会一直阻塞线程;Synchronized获取锁时,不能指定超时时间,阻塞线程会一直阻塞下去,直到获取到锁。

     3.获取锁时,AQS可以直接返回,不管是否获取到锁,不会阻塞线程;Synchronized,如果锁被其他线程获取了,当前线程只能阻塞等待。

     4.AQS可以有多个条件变量,来用于线程同步,且在等待条件变量时可以设置是否响应中断、是否指定超时时间、是否不阻塞;Synchronized只有一个条件变量,来用于线程同步,等待条件变量时(object.wait()),只能一直阻塞下去,等待被其他线程唤醒或者被中断唤醒。

     5.AQS可以是独占锁,也可以是共享锁;Synchronized只能是独占锁

     6.AQS可以是公平锁,也可以是非公平锁;Synchronized只能是非公平锁,不能保证先来的线程先获取到锁

 

二.原理

    1.获取锁的过程

     

i.获取锁时
    1.1如果锁空闲,设置为已占用状态后,直接返回锁成功(非公平锁,等待队列中的线程不一定能抢到锁)
    1.2直接把当前线程放到锁等待队列的末尾(公平锁),并调用park,线程进入睡眠状态
ii.释放锁时
    如果锁等待队列为空,直接设置锁为未锁定状态,返回
    否则找到锁等待队列第一个线程,把这个线程唤醒,这个线程唤醒后,会去争抢锁;如果争取失败,调用park,进入睡眠状态,该线程还在队列头
    如果队列头第一个线程抢到了锁,会把自己从锁等待队列中摘除。

   2.条件变量等待唤醒过程

1.进入等待时,把当前线程加入到等待队列,并调用park,线程进入睡眠状态。
2.唤醒某个线程时,找到等待队列中指定的线程,把这个线程唤醒,把这个线程从队列中摘除。

 

  3.独占锁API

    

1 void acquire(int args);//独占式获取同步状态,如果获取失败插入同步队列进行等待
2 void acquireInterruptibly(int arg);//在1的基础上,此方法可以在同步队列中响应中断
3 boolean tryAcquireNanos(int arg,long nanosTimeOut);//在2的基础上增加了超时等待功能,到了预计时间还未获得锁直接返回
4 boolean tryAcquire(int arg); //获取锁成功返回true、失败返回false
5 boolean release(int arg); //释放同步状态、该方法会唤醒在同步队列的下一个结点

 

   4.共享锁API

 

1 void acquireShared(int arg);//共享获取同步状态、同一时刻多个线程获取同步状态
2 void acquireSharedInterruptibly(int arg);//在1的基础上增加响应中断
3 boolean tryAcquireSharedNanos(int arg,long nanosTimeOut);//在2的基础上增加超时等待
4 boolean releaseShared(int arg);//共享式释放同步状态

 

   5.等待方法API

  

1 void await() throws InterruptedException;//同Object的await()、直到被中断或者唤醒
2 void awaitUninterruptibly(); //不响应中断、直到被唤醒
3 boolean await(long time, TimeUnit unit) throws InterruptedException; //同Object.wait(long timeout),多了自定义时间单位   中断、超时、被唤醒
4 boolean awaitUntil(Date deadline) throws InterruptedException; //支持设置截止时间;

   6.唤醒方法API

    

void signal(); //唤醒一个等待在Condition上的线程,将该线程由等待队列转移到同步队列中
void signalAll();//将所有等待在condition上的线程全部转移到同步队列中

 

posted @ 2022-02-17 17:31  高压锅里的大萝卜  阅读(82)  评论(0编辑  收藏  举报