美文网首页
java基础知识10-AQS

java基础知识10-AQS

作者: liwsh | 来源:发表于2021-05-07 21:48 被阅读0次

1.AQS核心思想

如果被请求的共享资源空闲,那么就将当前请求资源的线程设置为有效的工作线程,将共享资源设置为锁定状态;如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中。

2. 主要原理

AQS使用一个Volatile的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作,通过CAS完成对State值的修改


image.png

3. 阻塞和唤醒

获取不到锁的时候,进入阻塞队列,park在自身线程。一个线程执行完成后会释放锁,unpark排在队列的第一个线程,不会有惊群效应。park和unpark主要是用来阻塞和唤醒线程。

4. park unpark notify wait condition

image.png
1.park()/unpark()底层的原理是“二元信号量”,你可以把它相像成只有一个许可证的Semaphore,只不过这个信号量在重复执行unpark()的时候也不会再增加许可证,最多只有一个许可证
2.在java中,线程间的通信可以使用wait、notify、notifyAll来进行控制。wait进入synchronize获得锁之后释放锁等待唤醒。notify获得锁后释放锁,唤醒等待的线程。https://www.jianshu.com/p/f7d4819b7b24
3.wait()、notify()和notifyAll()是基于synchronized
Condition是基于Lock的。
Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。阻塞队列实际上是使用了Condition来模拟线程间协作。
  1. 因为notify是唤醒所有等待的线程,唤醒的可能不是我们想要唤醒的线程。如果需要精准唤醒某一类线程,应该使用condition。参考:https://www.jianshu.com/p/d3214bd34a2d
  2. condition 详解参考:https://www.jianshu.com/p/58651d446e03

5. 独占锁,共享锁

AQS定义两种资源共享方式
Exclusive(独占):只有一个线程能执行,如ReentrantLock。又可分为公平锁和非公平锁:
* 公平锁:按照线程在队列中的排队顺序,先到者先拿到锁
* 非公平锁:当线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的
Share(共享):多个线程可同时执行,如Semaphore/CountDownLatch。Semaphore、CountDownLatCh、 CyclicBarrier、ReadWriteLock 我们都会在后面讲到。

1.ReentrantReadWriteLock是ReadWriteLock接口的实现类。ReadWriteLock接口的核心方法是readLock(),writeLock()。实现了并发读、互斥写。但读锁会阻塞写锁,是悲观锁的策略
ReentrantReadWriteLock也是通过AQS来实现锁的,但是ReentrantReadWriteLock有两把锁:读锁和写锁,它们保护的都是同一个资源,那么如何用一个共享变量来区分锁是写锁还是读锁呢?答案就是按位拆分。
由于state是int类型的变量,在内存中占用4个字节,也就是32位。将其拆分为两部分:高16位和低16位,其中高16位用来表示读锁状态,低16位用来表示写锁状态。当设置读锁成功时,就将高16位加1,释放读锁时,将高16位减1;当设置写锁成功时,就将低16位加1,释放写锁时,将第16位减1

  1. StampedLock是java8在java.util.concurrent.locks新增的一个API 。
    该类是一个读写锁的改进,它的思想是读写锁中读不仅不阻塞读,同时也不应该阻塞写:在读的时候如果发生了写,则应当重读而不是在读的时候直接阻塞写!参考:https://duanguangguang.github.io/2018/12/31/concurrent/stampedlock/
  2. Semaphore(信号量)它通过 new Semaphore(permits) 来进行创建,permits 表示同一时间可以执行多少个线程。
    使用 acquire 来获得许可,通过 release 来释放许可。在同一时间只允许 permits 个线程同时运行。初始5个许可,acquire一次state--,如果state为小数则进入等待。release相反。
  3. CountDownLatch 内部维护了一个计数器,当计数器不为 0 的时候调用其 await() 可以进行阻塞,每次使用 countDown() 计数器值 - 1,当计数器值为 0 的时候,所阻塞的线程从 await() 返回
    利用这个特性我们可以用来合并多个线程最终的结果,或者以此来模拟并发请求调用等等,如下并发请求代码 参考https://juejin.cn/post/6844904032109068295
  4. CyclicBarrier 它可以实现让一组线程等待至某个状态之后再全部同时执行https://www.jianshu.com/p/4ef4bbf01811, 调用await方法,state--。 发现state不为0,则在condition上等待。 最后一个线程把state减为0的时候,唤醒所有在condition等待的线程。
  5. futureTask实现原理:https://zhuanlan.zhihu.com/p/40047276

参考文档:
clh队列:https://baiyp.ren/CLH%E9%98%9F%E5%88%97%E9%94%81.html
AQS原理:https://tech.meituan.com/2019/12/05/aqs-theory-and-apply.html
AQS详解:https://pdai.tech/md/java/thread/java-thread-x-lock-AbstractQueuedSynchronizer.html

相关文章

  • java基础知识10-AQS

    1.AQS核心思想 如果被请求的共享资源空闲,那么就将当前请求资源的线程设置为有效的工作线程,将共享资源设置为锁定...

  • Android 知识梳理目录 - 好吧,这是一个很"干

    一、Java 知识梳理 Java&Android 基础知识梳理(1) - 注解Java&Android 基础知识梳...

  • java基础知识

    title: java基础知识tags: [java基础知识] 位运算符 java种的运算符有 “&”,“|”,“...

  • Java基础知识整理(一)

    1.Java基础知识体系 2.Java技术体系平台 3.Java语言特点与核心机制 1.Java基础知识体系 2....

  • 大话Java持久层

    基础知识储备: Java SE(Java语言【java.lang】、Java集合框架【java.util】) Ja...

  • Android面试题4

    1 Java基础知识。线程,java虚拟机,内存模型等。2 Android基础知识。官方API,常用控件源码,自定...

  • Java 序列化

    title: Java 序列化categories: 后台开发tags: java 基础知识 必备 Java 序列...

  • Java基础知识脑图总结

    Java基础知识脑图总结

  • Android内存泄漏

    文章包括两部分: (1)java内存泄漏基础知识 (2)Android内存泄漏。 一.Java内存泄漏基础知识 1...

  • Java面试知识点汇总

    1.基础知识 【JAVA】JAVA 中的小知识(补充中...) 【JAVA】private、protected 和...

网友评论

      本文标题:java基础知识10-AQS

      本文链接:https://www.haomeiwen.com/subject/eyledltx.html