什么是线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中
线程池的作用
线程池作用就是限制系统中执行线程的数量
根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列
为什么使用线程池
1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)
Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService
什么时候使用线程池
创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率,例如:创建线程消耗时间T1,执行任务消耗时间T2,销毁线程消耗时间T3,如果T1+T3>T2,那么是不是说开启一个线程来执行这个任务太不划算了!正好,线程池缓存线程,可用已有的闲置线程来执行新任务,避免了T1+T3带来的系统开销
线程并发数量过多,抢占系统资源从而导致阻塞,我们知道线程能共享系统资源,如果同时执行的线程过多,就有可能导致系统资源不足而产生阻塞的情况,运用线程池能有效的控制线程最大并发数,避免以上的问题
对线程进行一些简单的管理,比如延时执行、定时循环执行的策略等运用线程池都能进行很好的实现
线程池ThreadPoolExecutor
线程池的顶级接口是Executor,具体实现为ThreadPoolExecutor类,ThreadPoolExecutor提供了四个构造函数
corePoolSize:核心线程的最大值,线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过corePoolSize,则新建的是非核心线程。核心线程即使是空闲状态也不会被销毁,调用allowCoreThreadTimeOut可以手动设置过xx时间后销毁线程
maximumPoolSize:该线程池中线程总数最大值,线程总数 = 核心线程数 + 非核心线程数
keepAliveTime:该线程池中非核心线程闲置超时时长,一个非核心线程,如果闲置状态的时长超过这个参数所设定的时长,就会被销毁掉
TimeUnit:keepAliveTime的单位,TimeUnit是一个枚举类型
workQueue:当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务
threadFactory:这是一个接口,是创建线程的方式
RejectedExecutionHandler:抛出异常专用的
向ThreadPoolExecutor添加任务
new一个ThreadPoolExecutor,new完了,就要通过通过ThreadPoolExecutor.execute(Runnable command)提交一个要执行的任务
ThreadPoolExecutor的策略
当一个任务被添加进线程池时:
线程数量未达到corePoolSize,则新建一个线程(核心线程)执行任务
线程数量达到了corePoolSize的最大值,则将任务移入队列等待
队列已满,新建线程(非核心线程)执行任务
队列已满,总线程数又达到了maximumPoolSize,就会由RejectedExecutionHandler抛出异常
常见四种线程池
CachedThreadPool():顾名思义,他是可缓存线程池,线程数无限制,有空闲线程则复用空闲线程,若无空闲线程则新建线程,一定程序减少频繁创建/销毁线程,减少系统开销
FixedThreadPool():定长线程池,可控制线程最大并发数(同时执行的线程数),超出的线程会在队列中等待
ScheduledThreadPool():支持定时及周期性任务执行
SingleThreadExecutor():有且只有一个工作线程执行任务,所有任务按照指定顺序执行,即遵循队列的入队出队规则
网友评论