JUC之八并发工具及AQS简单总结

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完成的。
JUC
JUC包下可以分为下面几类:

  1. atomic,基本类型、引用类型、累加器
  2. locks,读写锁、重入锁
  3. collections并发容器ConcurrentHashMap/ConcurrentSkipListMap及阻塞队列 BlockingQueue/CopyOnWriteArrayList
  4. executor执行框架与线程池,Future/Executor
  5. tools并发工具类,CountdownLatch/CyclicBarrier/Semaphore/Exchanger
AQS
state属性 AQS里有个重要的字段state,在不同的类里有着不同的含义:
  • 基于state实现的排它锁ReentrantLock,state 值为1代表锁被占用,值为0时代表锁未被占用。
  • 基于state实现的读写锁ReentrantReadWriteLock,state 被分成两部分,高16位记录读锁次数,低16位记录写锁次数。
  • 基于state实现的信号量Semaphore,初始化一个state值,表示最大限制数,即可以做到允许最多N个线程同时运行,达到限流效果。
  • 基于state实现的线程等待器CountDownLatch,初始化一个state值,state值为0时触发唤醒动作。
两个队列 AQS里有两个重要的队列:同步队列与等待队列。
  • 同步队列:维护唤醒线程的队列,获取互斥锁失败时入队的线程。
  • 等待队列:实现条件锁时用到的队列。调用await()的时候会释放锁,然后线程会加入到条件队列,调用signal()唤醒的时候会把条件队列中的线程节点移动到同步队列中,等待再次获得锁。
节点状态 AQS 定义了5个队列中节点状态:
  • 值为0,初始化状态,表示当前节点在sync队列中,等待着获取锁。
  • CANCELLED,值为1,表示当前的线程被取消。
  • SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark。
  • CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列。
  • PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执行。
【JUC之八并发工具及AQS简单总结】参考的文章:《Java并发编程的艺术》
AbstractQueuedSynchronizer(AQS) 总结篇

    推荐阅读