Base
-
进程: 每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)
-
线程: 同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
实现多线程
- 继承 Thread 类
- 实现 Runnable 接口
实现Runnable接口比继承Thread类所具有的优势:
-
可以避免java中的单继承的限制
-
线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类
线程池执行任务
Callable
Future
FutureTask
线程状态
创建、就绪、运行、阻塞、终止。
| New | Runnable | Running | Blocked | Dead |
|---|
线程安全
线程池
资源控制,线程管理,避免了线程反复创建销毁所带来的开销问题
- 反复创建销毁线程,开销大
- 过多的线程会占用太多内存
参数
corePoolSize
核心线程数
线程数添加规则:
-
如果线程数小于corePoolSize, 创建一个核心线程
-
如果线程数等于或大于corePoolSize, 但小于maxPoolSize, 则将任务放入队列
-
如果队列已满,并且线程数已满,则创建一个非核心新线程来执行任务
-
如果队列已满,并且线程数大于或等于maxPoolSize, 则拒绝该任务
判断顺序:corePoolSize > workQueue > maxPoolSize
maxPoolSize
最大线程数
keepAliveTime
多于corePoolSize的线程,超过keepAlveTime, 会被终止
非核心线程的alive time
ThreadFactory
默认使用Executors.defaultThreadFactory()来创建
也可以自定义ThreadFactory,就可以改变线程名,线程组,优先级,是否守护线程
workQueue
直接交接:SynchronousQueue 同步队列
无界队列:LinkedBlockingQueue
有界队列:ArrayBlockingQueue
workStealingQueue (since 1.8)
适合树的遍历,会产生很多子任务去执行
每个线程的子任务会放到自己的队列,其它线程也可以窃取这个队列中的任务,去帮助执行
Handler
拒绝时机
-
当Executor关闭时,提交的新任务会被拒绝
-
当使用有边界的队列饱和时,会拒绝新提交的任务
RejectPolicy:
-
AbortPolicy -- Default
抛出异常
-
DiscardPolicy
直接丢弃
-
DiscardOldestPolicy
丢弃队列中最老的
-
CallerRunsPolicy
让调用者跑任务
优点
-
避免了业务损失
-
降低提交的速度,相当于一种负反馈,只有在任务执行完毕后,才会继续提交任务,在这个期间,队列中的任务也执行了一些,相当与给线程池 一些缓冲的时间
-
手动创建线程池 -- 结合业务确定线程池
线程数的确定
JDK提供的线程池
newFixedThreadPool
newSingleThreadPool
newCachedThreadPool
newScheduleThreadPool
停止线程池
钩子方法
每个任务执行前后,日志,统计 自定义线程池,添加暂停和恢复功能