Python 官方文档:入门教程 => 点击学习
目录1、AQS 是什么?2、AQS 模型3、AQS state4、AQS 两种资源共享方式:5、模板方式实现自定义6、锁的分类:公平锁和非公平锁,乐观锁和悲观锁7、CAS8、总结1、
AQS 是类 AbstractQueuedSynchronizer的简称,也是常用锁的基类,比如常见的ReentrantLock,Semaphore,CountDownLatch 等等。
AQS提供了一种实现阻塞锁和一系列依赖FIFO等待队列的同步器的框架。是Java提供的一种模板,一般在现有同步器无法完成的时候可以自行扩展。当然也可以自己实现,不过既然有现成的为什么还要自己瞎鸡儿写。
注意:图来自网上,具体的原地点在哪我也不知道。如果有问题可以联系我。
解释:整个模型相当于在食堂吃饭,只开了一个窗口,只有一个打饭的师傅(state),所有想要吃饭的线程必须排队等待,直到轮到自己。
AQS就是基于队列,用共享变量state,线程通过CAS去改变状态符,成功则获取锁成功,失败则进入等待队列,等待被唤醒。代码解决现实问题,现实问题催生解决方案。
state 代表 共享资源和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。
state的访问方式有三种:
1.Exclusive:独占,只有一个线程能执行,如ReentrantLock
2.Share:共享,多个线程可以同时执行,如Semaphore、CountDownLatch、ReadWriteLock,CyclicBarrier。
不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共享资源state的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了。自定义时主要实现以下几种方法:
isHeldExclusively()
:该线程是否正在独占资源。只有用到condition才需要去实现它。tryAcquire(int)
:独占方式。尝试获取资源,成功则返回true,失败则返回false。tryRelease(int)
:独占方式。尝试释放资源,成功则返回true,失败则返回false。tryAcquireShared(int)
:共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。tryReleaseShared(int)
:共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。以ReentrantLock为例,state初始化为0,表示未锁定状态。A线程lock()时,会调用tryAcquire()独占该锁并将state+1。此后,其他线程再tryAcquire()时就会失败,直到A线程unlock()到state=0(即释放锁)为止,其它线程才有机会获取该锁。当然,释放锁之前,A线程自己是可以重复获取此锁的(state会累加),这就是可重入的概念。但要注意,获取多少次就要释放多么次,这样才能保证state是能回到零态的。
再以CountDownLatch以例,任务分为N个子线程去执行,state也初始化为N(注意N要与线程个数一致)。这N个子线程是并行执行的,每个子线程执行完后countDown()一次,state会CAS减1。等到所有子线程都执行完后(即state=0),会unpark()主调用线程,然后主调用线程就会从await()函数返回,继续后余动作。
一般来说,自定义同步器要么是独占方法,要么是共享方式,他们也只需实现tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一种即可。但AQS也支持自定义同步器同时实现独占和共享两种方式,如ReentrantReadWriteLock。
公平锁是严格的以FIFO的方式进行锁的竞争,但是非公平锁是无序的锁竞争,刚释放锁的线程很大程度上能比较快的获取到锁,队列中的线程只能等待,所以非公平锁可能会有“饥饿”的问题。但是重复的锁获取能减小线程之间的切换,而公平锁则是严格的线程切换,这样对操作系统的影响是比较大的,所以非公平锁的吞吐量是大于公平锁的,这也是为什么jdk将非公平锁作为默认的实现。
CAS(Compare And Swap),即比较并交换。是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。CAS有效地说明了“我认为位置V应该包含值A;如果包含该值,则将B放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。sun.misc.Unsafe 类提供了硬件级别的原子操作来实现这个CAS。java.util.concurrent 包下的大量类都使用了这个 Unsafe.java 类的CAS操作。Unsafe 包是c++的接口实现,直接可以访问计算机的内存等敏感操作,所以标记为Unsafe。
CAS 是直接调用计算机的硬件指令,是硬件级别的线程同步,也是一种乐观锁。
从整体上说了下AQS,没有深入到代码层级,先理解思想,后看具体实现。你理解了吗?下期具体分析一个CountDownLatch 源码,从细节理解AQS。
本篇文章就到这里了,希望能对你有所帮助,也希望您能够多多关注编程网的更多内容!
--结束END--
本文标题: 带你快速搞定java多线程(4)
本文链接: https://lsjlt.com/news/130499.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0