JUC 提供了几个并发工具,比方 CountDownLatch,CycelicBarrier,Semaphore 和 Exchanger。
Semaphore
又名计数信号量,量初始并保护肯定数量的许可证,应用之前先要先取得一个许可,用完之后再开释一个许可。当然也能够逆向应用,在结构 Semaphore 的时候传入 0 个许可,执行某个操作后增加一个许可,而后再放行期待的线程。
信号量通常用于限度线程的数量来管制拜访某些资源,从而达到单机限流的目标。
Semaphore 也是基于 AQS 框架来实现的,Semaphore 也有偏心和非偏心之说,Semaphore 反对重入取得许可。
CountDownLatch
容许一个或多个线程期待其它线程实现操作。在初始化的时候给定 CountDownLatch 一个计数,调用 await() 办法的线程会始终期待,其余线程执行完操作后调用 countDown(),当计数减到 0,调用 await() 办法的线程被唤醒继续执行。
CountDownLatch 没有减少计数的 API,所以不能够重复使用,如果要用能够重置计数的,能够应用 CyclicBarrier。
CountDownLatch 能够用在多个线程同时去操作各自的逻辑,等都完结后再对立汇总等业务场景。
Exchanger
用于进行线程间的数据交换。它提供了一个同步点,在这个同步点,两个线程能够进行数据交换,次要是通过 exchange() 这个办法进行,如果第一个线程先执行 exchange() 办法,它会始终期待第二个线程也执行 exchange() 办法,当两个线程都达到同步点时,就能够将本线程生产出的数据传递给对方。
Exchanger 外面有个外部类 Node,应用了 sun.misc.Contended 注解进行润饰,因为最大的缓存行为 128 个字节,应用 sun.misc.Contended 来减少 padding,能够使得任意两个可用 Node 不会再同一个缓存行中。
除了 Exchanger 外,其它三个类都是借助 AQS 实现的。
Exchanger 源码可参考:源码剖析:Exchanger 之数据交换器
JUC
JUC 包下能够分为上面几类:
- atomic,根本类型、援用类型、累加器
- locks,读写锁、重入锁
- collections 并发容器 ConcurrentHashMap/ConcurrentSkipListMap 及阻塞队列 BlockingQueue/CopyOnWriteArrayList
- executor 执行框架与线程池,Future/Executor
- tools 并发工具类,CountdownLatch/CyclicBarrier/Semaphore/Exchanger
AQS
1,state 属性
AQS 里有个重要的字段 state,在不同的类里有着不同的含意:
- 基于 state 实现的排它锁 ReentrantLock,state 值为 1 代表锁被占用,值为 0 时代表锁未被占用。
- 基于 state 实现的读写锁 ReentrantReadWriteLock,state 被分成两局部,高 16 位记录读锁次数,低 16 位记录写锁次数。
- 基于 state 实现的信号量 Semaphore,初始化一个 state 值,示意最大限度数,即能够做到容许最多 N 个线程同时运行,达到限流成果。
- 基于 state 实现的线程期待器 CountDownLatch,初始化一个 state 值,state 值为 0 时触发唤醒动作。
2,两个队列
AQS 里有两个重要的队列:同步队列与期待队列。
- 同步队列:保护唤醒线程的队列,获取互斥锁失败时入队的线程。
- 期待队列:实现条件锁时用到的队列。调用 await() 的时候会开释锁,而后线程会退出到条件队列,调用 signal() 唤醒的时候会把条件队列中的线程节点挪动到同步队列中,期待再次取得锁。
3,节点状态
AQS 定义了 5 个队列中节点状态:
- 值为 0,初始化状态,示意以后节点在 sync 队列中,期待着获取锁。
- CANCELLED,值为 1,示意以后的线程被勾销。
- SIGNAL,值为 -1,示意以后节点的后继节点蕴含的线程须要运行,也就是 unpark。
- CONDITION,值为 -2,示意以后节点在期待 condition,也就是在 condition 队列。
- PROPAGATE,值为 -3,示意以后场景下后续的 acquireShared 可能得以执行。
参考的文章:《Java 并发编程的艺术》
AbstractQueuedSynchronizer(AQS) 总结篇