Java线程池的使用
线程池就是放了线程的池子,它可以对池子里面的线程进行维护,有效避免了重复创建线程和销毁线程所耗费的时间
线程的七大参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {...}
corePoolSize:核心线程数,也就是线程池中的常驻线程,不管是否空闲都在池中,除非设置allowCoreThreadTimeOut,在超时时才会干掉核心线程
maximumPoolSize:线程池中允许的最大线程数
keepAliveTime:空闲线程的存活时间,这里是指除了核心线程外的空闲线程的存活时间,就算核心线程有空闲也不会被干掉
unit:keepAliveTime的单位
workQueue:任务队列,存提交但尚未执行的任务
threadFactory:创建线程的工厂
handler:拒绝策略,意思是当队列已满,并且最大线程数都在工作时执行拒绝策略
线程的执行流程
常用的三种线程池
单个线程
public class ThreadPool {
public static void main(String[]args){
//1、单个线程
ExecutorService executorService= Executors.newSingleThreadExecutor();
//2、多个线程,可自定义多少个线程
//ExecutorService executorService=Executors.newFixedThreadPool(5);
//3、没有边界的线程,因为线程个数是Integer.MAX_VALUE
//ExecutorService executorService=Executors.newCachedThreadPool();
for(int i=0;i<=10;i++){
final int j=i;
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t"+j);
});
}
//executorService.shutdown();
}
}
结果
自定义线程个数
public class ThreadPool {
public static void main(String[]args){
//1、单个线程
//ExecutorService executorService= Executors.newSingleThreadExecutor();
//2、多个线程,可自定义多少个线程
ExecutorService executorService=Executors.newFixedThreadPool(5);
//3、没有边界的线程,因为线程个数是Integer.MAX_VALUE
//ExecutorService executorService=Executors.newCachedThreadPool();
for(int i=0;i<=10;i++){
final int j=i;
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t"+j);
});
}
//executorService.shutdown();
}
}
结果,最大线程只有五个,可以从线程名字看出来
无边界线程个数
因为newCachedThreadPool内部实现的最大线程为Integer.MAX_VALUE,可以认为是无边界的
public class ThreadPool {
public static void main(String[]args){
//1、单个线程
//ExecutorService executorService= Executors.newSingleThreadExecutor();
//2、多个线程,可自定义多少个线程
//ExecutorService executorService=Executors.newFixedThreadPool(5);
//3、没有边界的线程,因为线程个数是Integer.MAX_VALUE
ExecutorService executorService=Executors.newCachedThreadPool();
for(int i=1;i<=10;i++){
final int j=i;
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t"+j);
try {
//稍微睡眠几毫秒,可以更清楚的看到使用的线程数
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
//executorService.shutdown();
}
}
从线程名字可以看出这里开了10个线程执行任务
自定义线程池的四种拒绝策略
第一种 AbortPolicy
ThreadPoolExecutor.AbortPolicy()是默认的拒绝策略,使用这个策略会直接抛出RejectedExecutionException 异常
public class ThreadPool {
public static void main(String[]args){
//1、单个线程
//ExecutorService executorService= Executors.newSingleThreadExecutor();
//2、多个线程,可自定义多少个线程
//ExecutorService executorService=Executors.newFixedThreadPool(5);
//3、没有边界的线程,因为线程个数是Integer.MAX_VALUE
//ExecutorService executorService=Executors.newCachedThreadPool();
//4、自定义线程池,当提交的任务个数大于最大线程数+队列任务数时会执行拒绝策略
ExecutorService executorService=new ThreadPoolExecutor(3,
5,
10L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(5),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
for(int i=1;i<=11;i++){
final int j=i;
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t"+j);
});
}
//executorService.shutdown();
}
}
第二种 CallerRunsPolicy
执行这个策略时,调用者自己运行任务
public class ThreadPool {
public static void main(String[]args){
//自定义线程池,当提交的任务个数大于最大线程数+队列任务数时会执行拒绝策略
ExecutorService executorService=new ThreadPoolExecutor(3,
5,
10L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(5),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
for(int i=1;i<=11;i++){
final int j=i;
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t"+j);
});
}
//executorService.shutdown();
}
}
这里可以看到主线程在运行一个任务
第三种 DiscardOldestPolicy
执行这个策略时,会把队列中等待时间最长的任务抛掉,然后把新任务加入队列
public class ThreadPool {
public static void main(String[]args){
//自定义线程池,当提交的任务个数大于最大线程数+队列任务数时会执行拒绝策略
ExecutorService executorService=new ThreadPoolExecutor(3,
5,
10L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(5),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy());
for(int i=1;i<=11;i++){
final int j=i;
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t"+j);
});
}
//executorService.shutdown();
}
}
我们总共提交了11个任务,但在这里只有10个任务,也就是说新加入的11把4给替换掉了
第四种 DiscardPolicy
如果线程池满了,直接把新提交的任务抛掉
public class ThreadPool {
public static void main(String[]args){
//自定义线程池,当提交的任务个数大于最大线程数+队列任务数时会执行拒绝策略
ExecutorService executorService=new ThreadPoolExecutor(3,
5,
10L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(5),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy());
for(int i=1;i<=11;i++){
final int j=i;
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t"+j);
});
}
//executorService.shutdown();
}
}
从下面可以看到11的任务直接被抛掉了
合理配置线程数
1、CPU密集型
线程个数=CPU核数+1
2、IO密集型
有两种:
线程个数=CPU核数*2
线程个数=CPU核数/1-阻塞系数,阻塞系数0.8-0.9