JUC
JUC
1、JUC概述
JUC就是java.util.concurrent工具包的简称。这是一个处理线程并发的工具包。
主要包括5大块:① executor ② collections ③ atomic ④locks
⑤ tools
2、AQS
ReentrantLock,state初始化为0,表示未锁状态。A线程lock()时,会调用tryAcquire()独占该锁并将state+1。此后,其他线程再tryAcquire()时就会失败,直到A线程unlock()到state=0(即释放锁)为⽌,其它线程才有机会获取该锁。当然,释放锁之前,A线程⾃⼰是可以重复获取此锁的(state会累加),这就是可重⼊的概念。但要注意,获取多少次就要释放多么次,这样才能保证state是能回到零态的。
3、unsafe
通过直接操作内存的⽅式来保证并发处理的安全性,使⽤的是硬件的安全机制sun.misc.Unsafe,这个类包含了⼤量的对C代码的操作,包括很多直接内存分配以及原⼦操作的调⽤,⽽它之所以标记为⾮安全的,是告诉你这个⾥⾯⼤量的⽅法调⽤都会存在安全隐患,需要⼩⼼使⽤,否则会导致严重的后果,例如在通过unsafe分配内存的时候,如果⾃⼰指定某些区域可能会导致⼀些类似C++⼀样的指针越界到其他进程的问题,不推荐直接使⽤unsafe来操作原⼦变量,⽽是通过java封装好的⼀些类来操作原⼦变量。
Unsafe 提供了以下功能:
1)内存管理
2)非常规的对象实例化 allocateInstance
3)操作类、对象、变量
4)操作数组
5)多线程同步。包括锁机制、CAS操作等
6)挂起与恢复
7)内存屏障
二、atomic
1、类型
基本类型:AtomicInteger、AtomicLong、AtomicBoolean;
引用类型:AtomicReference、AtomicReference的ABA问题(通过AtomicStampedRerence、AtomicMarkableReference解决)
数组类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray属性原⼦修改器 (Updater):AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater 。
AtomicReference 修改对象时,会出现ABA的问题。
AtomicStampedRefer 可以避免出现ABA的问题
2、AtomicIntegerFieldUpdater
限制1:操作的⽬标不能是static类型。
限制2:操作的⽬标不能是final类型的,因为final根本没法修改。
限制3:必须是volatile类型的数据,也就是数据本身是读⼀致的。
3、AtomicLong 和LongAdder
AtomicLong的原理
AtomicLong是通过依靠底层的CAS来保障原⼦性,在要添加或者减少的时候,会使⽤死循环不断地cas到特定的值,从⽽达到更新数据的⽬的。
LongAdder的原理
LongAdder是在AtomicLong的基础上将单点更新压⼒分散到各个节点,在低并发的时候通过对base的直接更新可以很好的保障和AtomicLong的性能基本保持⼀致,⽽在⾼并发的时候通过分散提⾼了性能。缺点就是LongAdder在统计的时候如果有并发更新,可能导致统计的数据有误差。
三、Tools
1、CountDownLatch
2、CyclicBarrier
3、Semaphore
限流
4、Exchanger
5、Executors
线程池,一般用executor callable 和future形成一个线程池框架;
线程池如何配参数?
IO型的,还是CPU密集型的。
第一种方案:如果是IO型的,可以把线程池大小配大一点儿!如果是CPU密集型的那就可以改小一点儿(根据CPU的核数去做处理)。
第二种方案:在你的机器资源足够的情况下,清楚知道你的接口的耗时是多少,要知道你的qbs多大。去设置线程数。如果qbs是100,你的耗时是10ms,那就需要10个线程。
三、Executor
1、Runnable
Runnable 是一个接口,简单就一个方法,实现run方法,在run方法里编写你执行的代码,不返回数据,并且不抛异常;
2、Callable
是一个接口,有call()方法,在call()方法里编写你要执行的代码,返回执行结果,也可以抛出异常。
Runnable 和 Callable一般不单独使用,一般配合FutrueTask加上ThreadPoolExecutor使用的
3、Future
也是1个接口,它可以对具体的Runnable 或者 Callable任务进行取消、判断是否已取消、查询任务是否完成、获取任务结果。
1、FutureTask
Future只是一个接口,无法直接用来创建对象使用,而FutureTask是一个类。它实现了RunnableFuture接口。RunnableFuture接口又继承了Runnable和Future
2、CompletableFuture
Java8后出现的。
三、ForkJoinPool
ForkJoinPool实现了ExecutorService的线程池,不同时使用了窃取机制。ForkJoinPool主要是为了执行ForkJoinTask而存在;ForkJoinPool线程池主要是为了对这些可递归可分解的任务进行调度执行。
加上⼀些对线程池⽣命周期的控制,以及提供⼀些对池的状态检查⽅法(例如 getStealCount),⽤于帮助开发、调优和监视fork/join应⽤程序。
窃取机制是什么?
窃取机制是所有被ForkJoinPool管理的线程尝试窃取提交到池子里的任务来执行,执行中又可产生子任务提交到池子中。
内部数据结构:ForkJoinPool采用了哈希数组+双端队列的方式存在任务。
任务分为两种:① 外部任务,通过excute、submit提交的外部任务
② 内部任务,ForkJoinWorkerThread工作线程通过fork/join分解出来的工作任务。
外部任务映射到哈希数组的偶数槽位,提交的双端队列称之为Submission Queue;
内部任务映射到哈希数组的奇数数槽位,提交的双端队列称之为work Queue;
三、Collections
1 、concurrentHashMap
是一个分段锁,segment;具体可以看(并发编程基础)
2、copyOnWriteX
写时复制