线程
使用方法
- 继承Thread类,重写run()方法
- 实现Runnable接口,实现run()方法,在使用时,需要new Thread(new MyRunnable()).start()
- 实现Callable接口,实现call()方法,该方法执行后,会有返回值;并且可能抛出异常;并且执行后,可以得到一个Future对象
并行和并发
- 并行:真正意义上的同时执行
- 并发:存在抢占cup资源和等待现象,只是同时运行的假象
线程池
线程池.pngExecutor
线程池的概念来源于Java中的Executor接口,其只有一个execute()方法。ExecutorService接口实现了该接口,增加了一些常用方法,一般所说的线程池接口,即指ExecutorService接口
真正的实现为ThreadPoolExecutor类
ThreadPoolExecutor
看一个常用的构造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
}
参数说明:
- corePoolSize
核心线程数,默认其会一直存活;当指定其allowCoreThreadTimeOut属性为true,则当闲置核心线程超过keepAliveTime时,会被终止 - maximumPoolSize
所能容纳最大线程数,超过该值,则后续新任务会被阻塞;
值 = 核心线程数 + 非核心线程数 - keepAliveTime
非核心线程超时时间;若设置了上述属性,则同样作用于核心线程 - unit
单位,不多说 - workQueue
execute方法提交的runnable对象会存储在该队列中 - threadFactory
为线程池提供新建线程的功能
执行任务原则
- 优先核心线程
- 线程数量大于等于核心线程数量,则任务被插入任务队列中排队等待
- 若2中无法插入(队列已满),若线程数量未达到线程池规定的最大值,则启动非核心线程执行
- 若3中已经达到最大值,则拒绝执行此任务,并调用rejectdExecution方法通知调用者(其中一个构造参数中可传入该对象)
简而言之,顺序为:核心线程-任务队列-非核心线程
如何提交任务?
这里提供了两种方法:
- execute(runnable); 该方法无法得到返回值
- Future future submit(callable); 执行一个任务,返回一个future对象,可以通过future.get()去获取返回值,get方法会一直阻塞,直到请求成功;
另外,get方法还可以设置一个超时时间,若超时还未完成,则会抛出异常,我们这时只需要catch异常实现自己的逻辑即可
常见分类
- FixedThreadPool
只有核心线程,且不会被回收,任务队列大小无限制 - CachedThreadPool
只有非核心线程,超时时长为60s;适合执行大量耗时少的任务
其他两种见导图
参考这位兄弟的博客
网友评论