三、VIP课程:并发编程专题->01-并发编程之Executor线程池详解
01-并发编程之Executor线程池详解
线程:什么是线程&多线程
线程:
线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
多线程:
多线程指在单个程序中可以同时运行多个不同的线程执行不同的任务。
多线程编程的目的, 就是“最大限度地利用 cpu 资源”, 当某一线程的处理不需要占用 cpu 而只和 io 等资源打交道时,让需要占用 CPU 的其他线程有其他机会获得 cpu 资源。从根本上说,这就是多线程编程的最终目的。
线程实现的方式:
Runnable接口、 Thread、 Callable接口
线程的生命周期&状态
线程的执行顺序:
实现 Runnable 接口相比继承 Thread 类有如下优势
1)可以避免由于 Java 的单继承特性而带来的局限
2)线程池只能放入实现 Runable 或 Callable 类线程,不能直接放入继承 Thread 的类
3)增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的
实现 Runnable 接口和实现 Callable 接口的区别
1)Runnable 是自从 java1.1 就有了,而 Callable 是 1.5 之后才加上去的
2)实现 Callable 接口的任务线程能返回执行结果,而实现 Runnable 接口的任务线程不能返回结果
3)Callable 接口的 call()方法允许抛出异常,而 Runnable 接口的 run()方法的异常只能在内部消化,不能继续上抛
4)加入线程池运行, Runnable 使用 ExecutorService 的 execute 方法, Callable 使用 submit 方法
注: Callable 接口支持返回执行结果,此时需要调用 FutureTask.get()方法实现,此方法会阻塞主线程直到获取返回结果,当不调用此方法时,主线程不会阻塞
Ctrl+Shift+B
使用&源码分析:
java.util.concurrent.ThreadPoolExecutor
内部工作原理(构造方法赋值)
• corePoolSize :池中所保存的线程数,包括空闲线程
• maximumPoolSize:池中允许的最大线程数
• keepAliveTime: 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间
• unit: keepAliveTime 参数的时间单位
• workQueue :执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务
• threadFactory:执行程序创建新线程时使用的工厂
• handler :由于超出线程范围和队列容量而使执行
线程池运行思路
如果当前池大小 poolSize 小于 corePoolSize ,则创建新线程执行任务
如果当前池大小 poolSize 大于 corePoolSize ,且等待队列未满,则进入等待队列
如果当前池大小 poolSize 大于 corePoolSize 且小于 maximumPoolSize ,且等待队列已满,则创建新线程
执行任务
如果当前池大小 poolSize 大于 corePoolSize 且大于 maximumPoolSize ,且等待队列已满,则调用拒绝策略,来处理该任务
线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列里是否还有线程任务需要执行,如果在 keepAliveTime 里等不到新的任务了,那么线程就会退出
我们自己的任务,还是他线程
Submit 和 execute 方法的不同处:
1、 有返回值和无返回值
2、 Task 不一样 futuretask 一个 task 本身
拒绝策略
线程池有四种拒绝策略:
AbortPolicy:抛出异常, 默认
CallerRunsPolicy:不使用线程池执行
DiscardPolicy:直接丢弃任务
DiscardOldestPolicy:丢弃队列中最旧的任务
对 于 线 程 池 选 择 的 拒 绝 策 略 可 以 通 过 RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
来设置。
Jps>jstack
jstack 是排查线程死锁
=======================================
参考资料
end