本章节主要讲述锁如何使用和如何实现。

  • Lock锁和synchronized锁的区别
  • [x] Lock锁的正确使用方式

  • [x] AQS是什么?以及使用方式

  • AQS中为实现类提供好的三个修改同步状态的方法
  • AQS可重写哪些方法?
  • AQS提供了哪些模板方法(已实现的方法)?
  • 通过AQS自定义一个锁
  • [ ] AQS的实现分析

  • [ ] ReetrantLock的可重入是如何实现的

  • [ ] ReetrantLock的公平锁是如何实现

  • [x] ReentrantReadWriteLock特性

  • [ ] ReentrantReadWriteLock实现分析

  • [x] LockSupport的作用?方法?JDK6增加方法的意义

  • [x] Object监视器与Condition接口的对比

  • Condition的实现分析

1. Lock锁和synchronized锁的区别

  • Lock需要手动获取和释放
  • 有获取锁的超时功能
  • 获取锁时可以被中断

    2.Lock锁的正确使用方式

    image.png

    3.AQS是什么?以及使用方式

    AQS是一个抽象类,是用来构建其他同步组件的基础框架。
    AQS使用int成员变量标识同步状态,FIFO队列完成线程的排队工作
    自定义同步组件和锁的实现方式:

  • 自定义同步器继承并实现AQS,

  • 自定义同步器需要放在自己实现的锁或其他同步组件的类内部
  • 锁或同步组件面向用户,同步器面向锁和同步组件。

    4.AQS中为实现类提供好的三个修改同步状态的方法

  • getState():获取当前同步器的状态

  • setState(int newState):设置当前同步状态
  • compareAndSetState(int expect,int update):CAS设置当前状态

    5.AQS可重写的方法

  • 是否独占模式:isHeldExclusively()
  • 独占模式重写方法:
    • boolean tryAcquire(int arg)独占式获取同步状态,查询当前同步状态,CAS设置状态
    • boolean tryRelease(int arg)独占式释放同步状态
  • 共享式重写方法:

    • int tryAcquireShared(int arg)共享式获取同步状态,返回大于等于0的值
    • boolean tryReleaseShared(int arg)共享式释放同步状态

      6.AQS提供了哪些模板方法(已实现的方法)?

      image.png
      模板方法主要分三类:

    • 独占式获取和释放同步状态

    • 共享式获取与释放同步状态
    • 查询同步队列的等待线程情况

7.通过AQS自定义一个锁

  1. public class Mutex implements Lock {
  2. private final Sync sync = new Sync();
  3. @Override
  4. public void lock(){
  5. sync.acquire(1);
  6. }
  7. @Override
  8. public boolean tryLock(){
  9. return sync.tryRelease(1);
  10. }
  11. @Override
  12. public Condition newCondition(){
  13. return sync.newCondition();
  14. }
  15. @Override
  16. public void unlock(){
  17. sync.release(1);
  18. }
  19. public boolean isLocked(){
  20. return sync.isHeldExclusively();
  21. }
  22. public boolean hasQueueThreads(){
  23. return sync.hasQueuedThreads();
  24. }
  25. @Override
  26. public void lockInterruptibly() throws InterruptedException {
  27. sync.acquireInterruptibly(1);
  28. }
  29. @Override
  30. public boolean tryLock(long timeout, TimeUnit timeUnit) throws InterruptedException {
  31. return sync.tryAcquireNanos(1,timeUnit.toNanos(timeout));
  32. }
  33. private static class Sync extends AbstractQueuedSynchronizer {
  34. protected Sync() {
  35. super();
  36. }
  37. /**
  38. * 是否是独占锁
  39. * @return
  40. */
  41. @Override
  42. protected boolean isHeldExclusively() {
  43. return getState()==1;
  44. }
  45. /**
  46. * 锁的方式是增加 1
  47. */
  48. @Override
  49. protected boolean tryAcquire(int arg) {
  50. if(compareAndSetState(0,1)){
  51. setExclusiveOwnerThread(Thread.currentThread());
  52. return true;
  53. }
  54. return false;
  55. }
  56. /**
  57. * 释放同步状态 -1
  58. */
  59. @Override
  60. protected boolean tryRelease(int arg) {
  61. if(getState()==0){
  62. throw new IllegalMonitorStateException();
  63. }
  64. setExclusiveOwnerThread(null);
  65. setState(0);
  66. return true;
  67. }
  68. Condition newCondition(){
  69. return new ConditionObject();
  70. }
  71. }
  72. }

独占式的锁需要重写 tryAcquiretryRelease,另外重写一个是否独占的方法。上面类来自本书。参考的是ReetrantLock类的实现

8.AQS的实现分析

见另外一篇文章

9.ReentrantLock的可重入如何实现

对于获取锁的线程再次获取该锁,将同步状态变量 ++即可
释放的时候也是同步状态变量—,减为0视为释放了锁。
具体可以看代码:nonfairTryAcquire()

10.ReentrantLock如何实现公平锁

可以看tryAcquire()方法,多判断了一个是否有前驱节点。没有前驱=节点说明这个线程就是先进入的。就可以获取得到锁。

11. ReentrantReadWriteLock特性

image.png

12. ReentrantReadWriteLock实现分析

见另一篇文章

13.LockSupport的作用?方法?JDK6增加方法的意义

  • 作用
    • 阻塞线程
    • 唤醒线程
  • 方法
    • park():阻塞(其实是等待)线程
    • parkNanos(long nanos):指定纳秒
    • parkUntil(long deadline):指定具体时间线
    • unpark(Thread thread):唤醒线程
  • JDK6新增方法
    • park(Objcet blocker)
    • parkNanos(Object blocker,long nanos)
    • parkUntil(Object blocker,long deadline)
  • 新增方法的意义
    • 方便定位问题

image.png

14.Object监视器与Condition接口的对比

image.png

  • Condition可以指定等待的时间
  • Condition在等待期间不响应中断,监视器的话会响应中断?

15.Condition的实现分析

见另一篇文章