- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章带你快速搞定java多线程(4)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
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.
本篇文章就到这里了,希望能对你有所帮助,也希望您能够多多关注我的更多内容! 。
原文链接:https://gamwatcher.blog.csdn.net/article/details/115982712 。
最后此篇关于带你快速搞定java多线程(4)的文章就讲到这里了,如果你想了解更多关于带你快速搞定java多线程(4)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是一名优秀的程序员,十分优秀!