线程池介绍:
把要使用的线程提前创建好,用完了也不要释放而是以备下次使用,就节省了创建/销毁线程的开销
在这个使用的过程中,并没有真的 频繁创建销毁,而是从线程池里,去线程使用,用完了还给线程池
线程池参数介绍
int corePoolSize 核心线程数(一个线程池里,最少得有多少个线程)
long maximumPoolSize 最大线程数(一个线程池里,最多最多能有多少个线程)
long keepAliveTime 保持存活时间
TimeUnit unit 时间单位
BlockingQueue<Runnable> workQueue 和定时器一样,线程池中可以持有很多的任务
使用Runnable 来作为描述任务的主体
也可以设置PriorityBlockingQueue 带有优先级
ThreadFactory threadFactory 线程工厂
该类提供了方法 方法封装new Thread 的操作,并且同时给Thread设置一些属性
RejectedExecutionHandler handler 拒绝策略
工厂模式:也是一种常见的设计模式,通过专门的"共厂类"/"工厂对象"来创建指定类的对象 通过这个工厂类,来创建线程对象 通过静态方法封装new 操作
拒绝策略
1.继续添加新任务,直接抛异常,新旧任务都不执行
2.新的任务由添加任务的线程执行 新任务会执行,但不是线程池执行,而是调用者执行
3.丢弃最老任务
4.丢弃最新任务,按原来的执行,新加的不管
线程池的工作流程
1. 创建线程池:需要创建一个线程池对象,可以通过调用相应的线程池构造函数来实现。在创建线程池时,需要指定线程池的大小,即可以容纳的线程数量。
2. 提交任务:一旦线程池创建成功,就可以向线程池提交任务。任务可以是实现了Runnable接口或Callable接口的对象。线程池会根据任务的类型来执行相应的操作。
3. 任务调度:线程池会根据任务的提交顺序和线程池的状态来调度任务的执行。当有任务提交时,线程池会选择一个空闲的线程来执行任务。如果所有线程都在执行任务,而且线程池的大小已经达到上限,新提交的任务将会进入等待队列,等待有空闲线程时再执行。
4. 线程执行任务:线程池中的线程会从等待队列中获取任务并执行。线程执行任务的过程包括调用任务的run方法或call方法,并处理任务的返回结果(如果有)。
5. 任务完成:当任务执行完成后,线程会返回线程池,并准备接受新的任务。线程池会根据需要继续调度任务的执行,直到线程池被显式关闭。
使用Executors 创建常见的线程池
ExecutorService service = Executors.newFixedThreadPool(4);
service.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
});
2.按需创建,不用设置固定值,用完也不会立即销毁,以备后用.
Executors.newCachedThreadPool();
3.单个线程池 创建只包含单个线程的线程池.
Executors.newSingleThreadExecutor();
4.设定 延迟时间后执行命令,或者定期执行命令. 是进阶版的 Timer.
Executors.newScheduledThreadPool(1);//定时器 通过线程池里的若干个线程去完成定时器的任务
什么时候使用Executors 什么时候使用ThreadPoolExecutor
简单使用一下时 用Executors 希望高度定制化时 用TreadPoolExecutor
创建线程池的时候,很多时候需要设定线程池的数量,这个数量设置多少合适?
只要是具体的数字,那就都是错的
由于程序的复杂性,很难直接对吸纳城池的线程数量进行估算,更合适的做法,通过实验/测试的做法找到合适的线程数目,尝试给线程池,设定不同的线程数目,分别进行性能测试,衡量每种线程数目下,总的时间开销,和系统资源占用的开销,找到这两者之间的合适的值