初始化线程池后,把任务丢进去,等待调度就可以了,使用起来比较方便。
JAVA中Thread是线程类,不建议直接使用Thread执行任务,在并发数量比较多的情况下,每个线程都是执行一个很短的时间就任务结束了,这样频繁创建线程会大大降低系统的效率,因为频繁的创建和销毁线程需要时间。而线程池可以复用,就是执行完一个任务,并不销毁,而是可以继续执行其它任务。
Thread的弊端
- 每次
new Thread()
创建对象,性能差。 - 线程缺乏统一管理,可能无限制创建线程,相互竞争,有可能占用过多系统资源导致死机或OOM。
- 不能多执行,定期执行,线程中断
线程池的优点
- 重用存在的线程,减少对象创建,消亡的开销,性能佳,降低资源消耗。
- 可以控制最大并发线程数,提高系统资源利用率,同时避免过多资源竞争,避免阻塞,提高响应速度。
- 提供定时执行,定期执行,单线程,并发数控制等功能,以提高线程的可管理性。
阿里发布的 Java 开发手册中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
Executors利用工厂模式向我们提供了4种线程池实现方式,但是并不推荐使用,原因是使用Executors创建线程池不会传入相关参数而使用默认值所以我们常常忽略了那些重要的参数(线程池大小、缓冲队列的类型等),而且默认使用的参数会导致资源浪费,不可取。
ThreadPoolExecutor介绍
构造函数和参数
java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类。
public class ThreadPoolExecutor extends AbstractExecutorService { /** 构造函数 1 */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {} /** 构造函数 2 */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {} /** 构造函数 3 */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {} <i>本文来源gaodai$ma#com搞$$代**码网</i> /** 构造函数 4 */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {} }
ThreadPoolExecutor类中提供了四个构造方法,在构造函数4中,参数最多,通过观察其他3个构造函数,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。
构造器中各个参数的含义
corePoolSize 核心线程池的大小,在创建了线程池后,默认情况下,线程池中没有任何的线程池,而是等任务过来了再去创建线程执行任务。除非调用了预创建线程的方法,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。当线程池中的线程数量到达corePoolSize后,就会把到达的任务放到缓存队列里面。
- prestartCoreThread() : 预创建一个核心线程,使其闲置等待工作。
- prestartAllCoreThreads() : 启动所有核心线程,导致它们空闲地等待工作。