JAVA-AQS

作者: 超人TIGA | 来源:发表于2021-03-15 14:19 被阅读0次
    什么是AQS?

    队列同步器AbstractQueuedSynchronizer(以下简称同步器或AQS),就是一个要来实现同步的基础框架。

    AQS如何实现同步?

    首先要了解AQS的设计模式,是模板设计模式。该模式定义一系列的抽象方法,交给子类去继承实现。例如自定义View也是这种设计模式,我们自定义View的时候,就必须实现Draw方法。
    而AQS的内部,会有一个int类型的状态变量state,使用同步器提供的3个方法(getState()、setState(int newState)和compareAndSetState(int expect,int update))来进行操作,因为它们能够保证状态的改变是安全的。

    CLH队列锁

    CLH队列锁也是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程仅仅在本地变量上自旋,它不断轮询前驱的状态,假设发现前驱释放了锁就结束自旋。
    ①每当有新任务,会先把任务包装成一个QNode对象,QNode里还包含一个引用myPred,指向上一个QNode;和一个locked变量。
    ②组成队列后,每一个QNode的myPred引用都会对前一个节点的locked变量进行自旋,直到前一个节点的locked值变为false,贬值不再需要锁了。
    ③当一个QNode释放锁后,就会把locked设置为false,同时回收前一个节点。

    Java中的AQS是CLH队列锁的一种变体实现。无非就是进行一些优化。
    例如自旋会耗时,所以会增加自旋的次数,自旋几次后会阻塞,等到锁被释放后进行notify或者notifyAll后再进行锁的获取。

    ReentrantLock的实现

    重入锁:就是同一个线程,可以多次获取同一个锁。每获取一次锁,state就会自增1,释放锁的时候就自减1,最后达到锁的完全释放。

    公平和非公平锁:ReentrantLock的构造函数中,默认的无参构造函数将会把Sync对象创建为NonfairSync对象,这是一个“非公平锁”;而另一个构造函数ReentrantLock(boolean fair)传入参数为true时将会把Sync对象创建为“公平锁”FairSync。
    nonfairTryAcquire(int acquires)方法,对于非公平锁,只要CAS设置同步状态成功,则表示当前线程获取了锁,而公平锁则不同。tryAcquire方法,该方法与nonfairTryAcquire(int acquires)比较,唯一不同的位置为判断条件多了hasQueuedPredecessors()方法,即加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回true,则表示有线程比当前线程更早地请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。

    JMM内存模型
    640.jpeg
    可见性

    可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
    由于线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量,那么对于共享变量V,它们首先是在自己的工作内存,之后再同步到主内存。可是并不会及时的刷到主存中,而是会有一定时间差。很明显,这个时候线程 A 对变量 V 的操作对于线程 B 而言就不具备可见性了 。
    要解决共享对象可见性这个问题,我们可以使用volatile关键字或者是加锁。

    原子性

    原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
    我们都知道CPU资源的分配都是以线程为单位的,并且是分时调用,操作系统允许某个进程执行一小段时间,例如 50 毫秒,过了 50 毫秒操作系统就会重新选择一个进程来执行(我们称为“任务切换”),这个 50 毫秒称为“时间片”。而任务的切换大多数是在时间片段结束以后,
    那么线程切换为什么会带来bug呢?因为操作系统做任务切换,可以发生在任何一条CPU 指令执行完!注意,是 CPU 指令,CPU 指令,CPU 指令,而不是高级语言里的一条语句。比如count++,在java里就是一句话,但高级语言里一条语句往往需要多条 CPU 指令完成。其实count++至少包含了三个CPU指令!

    volatile的实现原理

    volatile关键字修饰的变量会存在一个“lock:”的前缀。
    Lock前缀,Lock不是一种内存屏障,但是它能完成类似内存屏障的功能。Lock会对CPU总线和高速缓存加锁,可以理解为CPU指令级的一种锁。
    同时该指令会将当前处理器缓存行的数据直接写会到系统内存中,且这个写回内存的操作会使在其他CPU里缓存了该地址的数据无效。

    相关文章

      网友评论

          本文标题:JAVA-AQS

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