由于系统频繁创建线程和销毁线程成本是比较高的,尤其是需要大量短时间的线程,于是有了线程池,可以很好的提高系统性能。线程池在系统启动时,便创建大量的空闲线程,当将一个Runnable对象传给线程池时,线程池的其中一个线程便执行Runnable对象的run()方法,执行完后,线程并非销毁而是回到线程池进入空间状态,等待下一个任务的到来。线程池可以有效的控制并发线程的数量,不让它超过系统值,而引起的JVM崩溃。
ThreadPoolExecutor是线程池里最核心的一个类,我们来通过它了解线程池:
ThreadPoolExecutor构造器可以看出ThreadPoolExecutor类给了4个构造器供我们使用,下面我们来详解构造器的7个参数:
corePoolSize———该池中的最大核心线程数量,核心线程默认保存在池中,即使是空闲状态的,除非设置了allowCoreThreadTimeOut为true(设置这个后,核心线程闲置一定时间(由下面的参数决定时间)后,就会被销毁掉)。
maximumPoolSize———允许线程池的最大线程数量(最大线程数量=核心线程数量+非核心线程数量)。
keepAliveTime———空闲状态下的非核心线程被销毁前等待的时间(核心线程设置了 allowCoreThreadTimeOut的话同样)。
unit———keepAliveTime的单位,枚举类型,有7个静态属性:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
workQueue———用于在执行任务之前使用的队列(就是添加线程任务后,任务进入队列后,不同的队列执行不同的策略),常用的类型有如下几种:
SynchronousQueue:队列接收到任务,直接提交给线程池处理,不保留它,如果所有线程都在工作了,则新建一个线程来处理这个任务。(线程数超过maximumPoolSize会不能新建线程而报错,一般把maximumPoolSize设置为Integer.MAX_VAULE)
LinkedBlockingQueue:队列接收到任务,如果当前线程数不超过corePoolSize,既新建核心线程执行这个任务,否则任务入队列等待。
ArrayBlockingQueue:指定队列的长度,如果当前线程未超过corePoolSize,新建核心线程处理任务,若超过了,则入队列等待,又如果队列已满,则新建非核心线程执行任务,再则总线程数超过了最大线程数,则发生错误。
DelayQueue:队列内元素必须实现Delayed接口(传入的任务必须先实现Delayed接口),先入队,到指定时间后才执行。
threadFactory———线程工厂,创建线程的方式。
handler———抛出异常专用,针对上面出现的异常的处理方式。
ThreadPoolExecutor类的几个常用方法:
execute(Runnable command):提交接受到的任务。
shutdown():队列不在接受新的任务,线程池内的任务执行完后,关闭线程池。
shutdownNow():队列不接受新的任务,并且队列内任务移除,并尝试停止正在执行的任务,关闭线程池。
ThreadPoolExecutor类让我们能自主定义出需要的各种线程池,但是每次使用线程池的时候,不想搞这么多参数怎么办?于是Java提供了4中常见的线程池供我们直接使用(通过Executors类创建):
CachedThreadPool(可缓存线程池)
ExecutorService cachedThreadPool=Executor.newCachedThreadPool();
源码:
规则:1.线程数量无限制
2.有空闲线程用空闲线程,无空闲线程则新建线程。
FixedThreadPool(定长线程池)
ExecutorService fixedThreadPool=Executors.newFixedThreadPool(int nThread);
源码:
规则:1.控制线程最大并发数(即同时执行的线程)
2.超出的线程在队列中等待。
SingleThreadExecutor(单线程化的线程池)
ExecutorService singleThreadExecutor=Executors.newSingleThreadExecutor();
源码:
规则:1.有且只有一个线程执行。
2.任务根据入队列规则执行,即先入队列先执行。
ScheduledThreadPool(调度型线程池)
ExecutorService scheduledThreadPool=Executors.newScheduledThreadPool(int corePoolSize);
源码:
规则:1.一定时间后执行或周期性执行。
不难发先,这些常用的线程池其实就是变相调用ThreadPoolExecutor类, 所以说要是没有我们想要的,还是老老实实的写吧。
线程池添加任务有submit和execute,它们的区别:
1.接受的参数不一样
2.submit有返回值
3.execute是Executor接口中唯一定义的方法,submit是ExecutorService接口定义的方法(该接口继承Executor接口)
网友评论