概述:线程池是一种可以复用线程的技术;
意义:
线程是稀缺资源,它创建与销毁是相对偏重且耗资源的操作;线程池就是一个线程缓存,负责对线程进行统一分配、调优与监控。
优势:
1、提高效率,创建好一定数量的线程放在池中等待,比需要时重新创建要快的多
2、减少创建和销毁的次数
3、提高响应速度
创建方式:
Executors类(并发包)提供了4种创建线程池方法,这些方法最终都是通过配置ThreadPoolExecutor的不同参数,来达到不同的线程管理效果
newCacheTreadPool
创建一个可以缓存的线程池,如果线程池长度超过处理需要,可以灵活回收空闲线程,没回收的话就新建线程
public static void main(String[] args) {
// 创建可缓存线程池
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
//创建任务
Runnable runnable = new Runnable(){
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
};
newCachedThreadPool.execute(runnable);
}
}
线程池的最大核心线程为无限大,当执行第二个任务时第一个任务已经完成,则会复用执行第一个任务的线程;如果第一个线程任务还没有完成则会新建一个线程
newFixedThread
创建一个定长的线程池,可控制最大并发数,超出的线程进行队列等待
public static void main(String[] args) {
// 创建定长线程池
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
for (int i = 0; i < 5; i++) {
//创建任务
Runnable runnable = new Runnable(){
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
};
// 将任务交给线程池管理
newFixedThreadPool.execute(runnable);
}
}
创建指定长度的线程池,任务超出当前线程池执行线程数量则会一直等待,直到运行。
newScheduleThreadPool
可以创建定长的、支持定时任务,周期任务执行。
public static void main(String[] args) {
// 创建支持定时线程池
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(2);
for (int i = 0; i < 5; i++) {
//创建任务
Runnable runnable = new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
// 将任务交给线程池管理,延迟2秒后才开始执行线程池中的所有任务
newScheduledThreadPool.schedule(runnable, 2, TimeUnit.SECONDS);
}
}
以下案例中延迟2秒后开始执行线程池中的所有任务
newSingleExecutor
创建一个单线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
public static void main(String[] args) {
// 创建单线程-线程池,任务依次执行
ExecutorService newScheduledThreadPool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
//创建任务
Runnable runnable = new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
// 将任务交给线程池管理
newScheduledThreadPool.execute(runnable);
}
}
工作原理:
ThreadPoolExecutor :
/**
* 用给定的初始参数创建一个新的ThreadPoolExecutor。
*/
public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
int maximumPoolSize,//线程池的最大线程数
long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
四大策略:
new ThreadPoolExecutor.AbortPolicy():
队列满了,直接丢弃,并抛出异常
new ThreadPoolExecutor.CallerRunsPolicy():
队列满了,直接丢弃任务,不抛出异常
new ThreadPoolExecutor.DiscardPolicy():
队列满了,丢弃等待最久未处理的任务,并加入到等待队列中
new ThreadPoolExecutor.DiscardOldestPolicy():
队列满了,直接在主线程中运行,不再进入线程池
最大线程数目调优:
CPU密集型:CPU集合,最大线程数就是几,可以保持CPU效率最高
IO密集型:判断程序中十分耗IO的线程,大于它 (两倍)15个 就设30