AQS面试必问


AQS概念:

  AbstractQuenedSynchronizer抽象队列同步器 简称AQS,是一种锁机制。

  在java.util .concurrent工具包中,这个包简称JUC。   AQS底层实现原理:   AQS维护了一个volatile修饰的共享变量state和一个FIFO线程等待队列,多线程争用资源被阻塞的时候就会进入这个队列。state是共享变量,其访问方式有如下三种:getState()、setState()、compareAndSetState(),通过尝试获取共享变量state的结果来对线程的状态作出处理   AQS是将每一条请求共享资源的线程封装成一个CLH队列(虚拟的双向队列)的一个结点来实现锁的分配。根据volatile修饰的state共享变量,线程通过CAS(Compare and swap)去改变状态。如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态,如果被请求的共享资源被占用,那么就需要一套线程阻塞等等以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现,即将暂时获取不到锁的线程加入到队列中等待被唤醒。    原理总结:AQS 就是基于CLH队列,用volatile修饰共享变量state,线程通过CAS去改变状态符,成功则获取锁成功,失败则进入等待队列,等待被唤醒。   AQS典型实现类和资源共享方式
  • 实现了AQS的锁有:ReentrantLock、Semaphore、CountDownLatch、CylicBarrier、ReentrantReadWriteLock都是AQS的衍生物
  • 独占,只有一个线程能执行,如ReentrantLock
  • 共享,多个线程可以同时执行,如:Semaphore、CountDownLatch、CylicBarrier
  • 独占和共享:ReentrantReadWriteLock

AQS实现类---ReentrantLock

  • state初始化为0,表示未锁定状态,A线程lock()时,会调用tryAcquire()独占锁并将state+1。
  • 之后其他线程在想tryAcquire的时候就会失败,直到A线程unlock() 到state = 0为止,其他线程才有机会获取该锁
  • A释放锁之前,自己也是可以重复获取此锁(state累加),这就是可重入的概念

AQS实现类---CountDownLatch

  • 任务分N个子线程去执行,state就初始化为N,N个线程并执行
  • 每个线程执行完之后countDown()一次,state就好CAS减一
  • 当N子线程全部执行完毕,state = 0,会unpark()主调用线程,主调用线程就会从await()函数返回,继续之后的动作