线程池概述:
什么是线程池?
线程池是一个可以复用线程的技术。
不使用线程池的问题
如果每个用户每次发送一个请求,后台就创建一个新线程来处理,那么创建的线程数之多,而创建线程的开销很大。这样会严重影响系统性能。
如何获得到线程池对象
使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程对象
TreadPoolExecutor构造器的参数说明
corePoolSize:核心线程的数量---->不能小于0
maximunPoolSize:最大线程数---->最大数量>=核心线程数量
keepAliveTime:临时线程的最大存活时间----->不能小于0
unit:存活时间的单位(秒、分、时、天)---->时间单位
workQueue:指定任务队列---->不能为null
threadFactory:线程工厂---->不能为null
handler:指定线程忙,任务满的时候,新任务来了怎么办---->不能为null
常见面试问题
临时线程什么时候创建?
新任务提交时发现核心线程忙,任务队列也满了,并且可以创建临时线程,此时才会创建临时线程。
什么时候会开始拒绝任务?
核心线程和临时线程都在忙,任务队列也满了,新的任务过来时候才开始拒绝。
线程池处理Runnable任务
1、创建Runnable实体类
package com.itheima.d6_safePool;
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"输出了:"+i);
}
try {
System.out.println(Thread.currentThread().getName()+"睡着了");
Thread.sleep(500000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2、测试方法
package com.itheima.d6_safePool;
import java.util.concurrent.*;
/*
* 创建线程池对象,并测试其特性
* */
public class safePoolDemo1 {
public static void main(String[] args) {
//1.创建线程池对象
/*
* this.corePoolSize 核心线程数
this.maximumPoolSize 最大线程数
this.workQueue 等待队列
this.keepAliveTime 等待时间
this.unit 时间类型
this.threadFactory 线程工厂
this.handler 任务拒绝策列
* */
ExecutorService pool = new ThreadPoolExecutor(3,5,4, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
//2.给任务线程池处理
Runnable target = new MyRunnable();
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
//pool.execute(target);
//关闭线程池,直接关闭不管任务完没完成 不建议使用
// pool.shutdownNow();
//关闭线程池,等待线程任务结束
// pool.shutdown();
}
}
线程池通过execute方法处理Runnable任务
线程池处理Callable任务
1、创建Callable实体类
package com.itheima.d6_safePool;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
private int n;
public MyCallable(int n) {
this.n = n;
}
@Override
public String call() throws Exception {
int sum=0;
for (int i = 0; i < n; i++) {
sum+=i;
}
return "子线程执行的结果是:"+sum;
}
}
2、测试方法
package com.itheima.d6_safePool;
import java.util.concurrent.*;
/*
* 创建线程池对象,并测试其特性
* */
public class safePoolDemo2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1.创建线程池对象
/*
* this.corePoolSize 核心线程数
this.maximumPoolSize 最大线程数
this.workQueue 等待队列
this.keepAliveTime 等待时间
this.unit 时间类型
this.threadFactory 线程工厂
this.handler 任务拒绝策列
* */
ExecutorService pool = new ThreadPoolExecutor(3,5,4, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
//2.给任务线程池处理
Future<String> f1 = pool.submit(new MyCallable(100));
Future<String> f2 = pool.submit(new MyCallable(200));
Future<String> f3 = pool.submit(new MyCallable(300));
Future<String> f4 = pool.submit(new MyCallable(400));
Future<String> f5 = pool.submit(new MyCallable(500));
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
System.out.println(f4.get());
System.out.println(f5.get());
}
}
线程池通过execute方法处理Callable任务
Executors工具类实现线程池
Executors:线程池的工具类通过调用方法返回不同类型的线程池对象
public static ExecutorService newCachedThreadPool():线程数量会随着任务增加而增加,如果线程任务完毕且空闲一段时间后会被回收掉。
public static ExecutorService newFixedThreadPool(int nThreads):创建固定数量的线程,如果某个线程因为异常而结束,那么线程池会补充一个新线程代替它。
public static ExecutorService newSingleThreadExecutor ():创建只有一个线程的线程池对象,如果该线程出现异常就会补充一个新线程。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize):可以实现在给定的延迟后运行任务,或者定期执行任务。
例:
package com.itheima.d6_safePool;
import java.util.concurrent.*;
/*
* 使用Executors工具类实现线程池
* */
public class safePoolDemo3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1.创建固定线程数据的线程池
ExecutorService pool =Executors.newScheduledThreadPool(3);
//2.给任务线程池处理
Runnable runnable = new MyRunnable();
pool.execute(runnable);
pool.execute(runnable);
pool.execute(runnable);
pool.execute(runnable);
}
}
Executors使用可能存在的陷阱
newFixedThreadPool(int nThreads),newSingleThreadExecutor ():因为创建固定的线程,而没有设置任务等待数,所以有可能会出现等待任务过多导致内存资源的损耗。
newCachedThreadPool(),newScheduledThreadPool(int corePoolSize):因为创建的线程数量随着任务数量增加,也会出现内存资源的损耗。