赞
踩
J.U.C(java.util.concurrent)在jdk1.5引入,引入J.U.C大大提高了java的并发性能,AQS(AbstractQueuedSynchronizer的缩写) 可以认为是J.U.C的核心,AQS 可以说是并发类中的重中之重,AQS 提供了基于firstIn,firstOut队列,这个队列可以用来构建锁或者其他相关的同步装置的基础框架
AQS底层是双向链表,是队列的一种实现,也可以当做队列,其中,Sync queue 是双向链表,其中包括head节点,tail节点,condition queue 不是必须的,condition queue 是个单项链表,只有当程序需要使用condition时,才会创建condition queue ,并且可能会有多个condition queue
(1)、使用Node实现FIFO队列,可以用于构建锁或者其他同步装置的基础框架
(2)、利用了一个int类型表示状态(在AQS类中有个stack成员变量,基于AQS有个同步组件ReentrantLock,stack表示获取锁的线程数,0表线程还没有获取锁,1表示已经有线程获取了锁,大于1表示重入锁的数量;)
(3)、使用方法是继承,AQS设计是基于模板方法,使用时,需要继承AQS,并且复写其中的方法。
(4)、子类通过继承并通过实现它的方法管理其状态{acquire和release}的方法操纵状态;
(5)、可以同时实现排他锁和共享锁模式(独占、共享)(站着使用者角度,AQS功能主要分为两类:独占功能和共享功能,要么实现独占功能,要么实现共享锁功能,而不会同时使用独占和共享功能)
首先AQS内部维护了一个clh队列来管理锁,线程首先尝试获取锁,如果失败,就将当前线程已经等待的信息包装成一个Node节点,加入到同步队列syn queue 中,接着不断循环尝试获取锁,条件是当前节点head,直接后进才会尝试,如果失败就会阻塞自己,只到自己被唤醒,而当持有锁线程释放锁时,会唤醒队列中的后进线程,基于这些基础的设计和思路,jkd提供了很多基于AQS的子类,即常用的同步组件:
1、CountDownLacth :是闭锁,通过计数来保证线程是否一直阻塞
2、Semaphore :可以控制同一时间并发线程的数目
3、CyclicBarrier
4、ReentrantLock
5、Condition
6、FutureTask
CountDownLacth 是同步辅助类,通过它可以完成类似于阻塞当前线程的功能,换句话说,就是一个线程一直处于等待状态,只到其他的线程执行的操作完成。CountDownLacth用了一个给定的计数器来进行初始化,这个计数器是原子操作,就是同一时刻只能有一个线程操作该计数器,计数器是不能被重置的,只能用一次。
CountDownLatch
CountDownLatch使用场景:
在某些场景中,程序执行需要等待某个条件后,才能执行后续的操作,典型的应用:并行运算,当某个处理任务很大时,可以把一个大的计算拆分为多个并行执行的子任务,当所有子任务计算都完成时,在将子任务运算结果组装成最终结果。
例子1:
执行结果:
例子2:
执行结果:
可以控制并发访问个数,Semaphore 也有两个核心方法,acquire()和release() ,acquire()是获取一个可以运行的许可,release()则是在操作完成后释放一个许可出来,Semaphore 通过同步机制,来控制同步访问的个数,
Semaphore使用场景
Semaphore常用于仅能提供有限的资源,比如连接数据库,这里可以控制连接数据库数量,以防止数据库因连接过多,导致异常
例子1:
执行结果:每一秒输出一段
例子2:
例子3:
执行结果:
例子:
执行结果:执行5次输出,后续线程丢弃
尝试获取许可方法:
tryAcquire():尝试获取1个许可,获取不到直接丢弃线程
tryAcquire(int permits): 尝试获取permits个许可,获取不到直接丢弃线程
tryAcquire(int permits, long timeout, TimeUnit unit): 尝试获取permits个许可,并设置超时时间
tryAcquire(long timeout, TimeUnit unit):尝试获取许可,并设置超时时间
CyclicBarrier 也是同步辅助类,允许一组线程相互等待,只到到达某个公共的屏障点(common barrier point),通过CyclicBarrier 可以完成多个线程的相互等待,只有当所有线程都就绪后才能各自继续执行下面的操作,CyclicBarrier 与CountDownLatch 有些相似的地方,都是通过计数器实现。
当某个线程调用await()方法,计数器加一,当计数器的值达到了我们设置的初始值时,因调用await()方法处于等待状态的线程会被唤醒,继续执行后续操作。
由于CyclicBarrier 释放后可以重用,所以也称为循环屏障。
CyclicBarrier 使用场景:
也可以用于多线程计算数据,最后合并结果的场景
CyclicBarrier 与CountDownLatch 区别:
(1)、CountDownLatch 计数器只能使用一次,CyclicBarrier 计数器用reset方法重置,循环使用
(2)、CountDownLatch,描述的是一个或N个线程等待其他线程的关系(等待完成某项操作,强调完成某项操作),CyclicBarrier,各个线程之间内部相互等待的关系。(所有的线程必须全部到达栅栏位置,才继续执行,强调线程)。
例子1:
执行结果:
例子2:
执行结果:捕捉抛出的异常后,但是可以继续执行下面的代码
正常应该捕获3个异常
注意,如果想保证代码正常执行,一定要保证不能抛出异常,或者将异常捕获,才能继续执行后续代码
例子3:
执行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。