目录
(1)并发工具类
(2)原子自增类
(3)线程池
一:并发工具类
-
CountDownLatch:允许一个或多个线程等待其他线程完成操作。
CountDownLatch不能重新初始化或者修改CountDownLatch对象的内部计数器的值(共享同步状态)。 -
CyclicBarrier:可循环使用的屏障。
让一组线程到达一个屏障/同步点时被阻塞,直到最后1个线程到达屏障时屏障才开门,所有被屏障的线程才会继续运行。 -
Semaphore:信号量
用来控制同时访问特定资源的线程数量。
二:原子操作类
java.util.concurrent.atomic中的原子操作类,CAS方式实现:
- 原子更新基本类型 (原子的方式更新基本类型)
- 原子更新数组 (原子的方式更新数组的某个元素)
- 原子更新引用 (原子的方式更新引用类型提供的类)
- 原子更新属性(字段) (原子的方式更新某个类里的某个字段)
三:线程池
1 线程池的好处
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,
还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。
2 线程池的实现原理
ThreadPoolExecutor任务执行过程:
1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步骤需要获取全局锁)。 即使其他空闲的基本线程能够执行新任务也会创建线程。
2)如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。
3)如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(注意,执行这一步骤需要获取全局锁)。
4)如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。
ThreadPoolExecutor采取上述步骤的总体设计思路,是为了在执行execute()方法时,尽可能地避免获取全局锁(那将会是一个严重的可伸缩瓶颈)
在ThreadPoolExecutor完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局锁。
3 相关参数
- keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。
任务队列空闲后,默认核心线程会阻塞在queue.take上,可重入锁,其它线程会被释放;
4 线程池配置
- 任务的性质:CPU密集型任务、IO密集型任务和混合型任务
CPU密集型任务应配置尽可能小的线程,如配置Ncpu+1个线程的线程池。由于IO密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如2*Ncpu。混合型的任务, - 任务的优先级:高、中和低。
优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。它可以让优先级高的任务先执行。 - 任务的执行时间:长、中和短。
执行时间不同的任务可以交给不同规模的线程池来处理,或者可以使用优先级队列,让执行时间短的任务先执行。