最近一直在总结多线程相关的知识点,为了解决多线程下安全性的问题,java提供了各种手段
1.锁功能,synchronized以及各种Lock,还有volatile、final关键字
2.支持并发的容器,如CurrentHashMap、BlockingQueue
3.用于同步的工具,如基于AQS实现的工具集
4.基于CAS的无锁操作
这些工具都是提供给多线程使用的,作为并发程序中的主角之一“多线程”,也是应该有规范使用机制。对于计算机来说线程是一种宝贵的资源,线程太少,并发功能就利用率就低;线程太多,会占用太多的系统资源。java中使用线程池的概念来规范多线程的使用。一下是线程池的处理流程图
线程池技术的具体使用方法
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize
– 池中所保存的线程数,包括空闲线程。如果运行的线程少于 corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。maximumPoolSize
– 池中允许的最大线程数。如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,则仅当workQueue队列满时才创建新线程。- keepAliveTime – 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
- unit – keepAliveTime 参数的时间单位。
workQueue
– 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。- threadFactory – 执行程序创建新线程时使用的工厂。
handler
– RejectedExecutionHandler由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。AbortPolicy
:直接抛出异常。CallerRunsPolicy
:只用调用者所在线程来运行任务。DiscardOldestPolicy
:丢弃工作队列里最近的一个任务,并执行当前任务。DiscardPolicy
:不处理,丢弃掉。- 当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
mainLock
对整个ThreadPoolExecutor对象的锁,修改poolSize, corePoolSize,- maximumPoolSize, runState和workers set需要加锁。
workers
存储工作线程对应Worker对象的HashSet,Worker类既是一个Runnable,也有一个ReentrantLock成员,poolSize为works的大小termination
线程池ThreadPoolExecutor对象的生命周期终止条件,和mainLock相关largestPoolSize
线程池跑过的最大线程数completedTaskCount
完成任务数- 向线程池提交任务,
submit
相对execute
有返回值,可取消,而且方便处理异常,submit调用了execute,submit提交的任务类型为RunnableFuture
(FutureTask
)。 ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor利用DelayQueue(lock、Condition和优先级队列)来实现线程的调度- 线程池状态:
RUNNING
在ThreadPoolExecutor被实例化的时候就是这个状态SHUTDOWN
通常是已经执行过shutdown()方法,不再接受新任务,等待线程池中和队列中任务完成STOP
通常是已经执行过shutdownNow()方法,不接受新任务,队列中的任务也不再执行,并尝试终止线程池中的线程TERMINATED
terminated()(调用shutdown
或者corePoolSize
为0会自动关闭时)行完毕,就会到达这个状态,ThreadPoolExecutor终结