线程池
线程池概述
线程池就是一个可以复用线程的技术
不使用线程池的问题
如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能
线程池的工作原理
线程池实现的API 参数
代表线程池的接口: ExecutorService
如何得到线程池对象
方式一 : 使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
方式二 : 使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象
ThreadPoolExecutor构造器参数说明
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数一:指定线程池的线程数量(核心线程):corePoolSize------>不能小于0
参数二:指定线程池可支持的最大线程数 : maxmumPoolSize------>最大数量 >= 核心线程数量
参数三:指定临时线程的最大存活时间 : keepAliveTime------>不能小于0
参数四:指定存活时间的单位(秒 分 时 天):unit------>时间单位
参数五:指定任务队列:workQueue------>不能为null
参数六:指定用哪个工厂创建线程:threadFactory------>不能为null
参数七:指定线程忙,任务满的时候,新任务来了怎么办:handler------>不能为null
常见面试题
1.临时线程什么时候创建?
新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程
2.什么时候会开始拒绝任务?
核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝
线程池处理Runnable任务
ExecutorService的常用方法
方法名称 | 说明 |
---|---|
void execute(Runnable command) | 执行任务/命令,没有返回值,一般用来执行Runnable任务 |
Future submit(Callable task) | 执行任务,返回未来任务对象获取线程结果,一般拿来执行Callable任务 |
void shutdown() | 等任务执行完毕后关闭线程池 |
List shutdown() | 立刻关闭,停止正在执行的任务,并返回队列中未执行的任务 |
package ThreadPool;
import java.util.concurrent.*;
public class ThreadPoolDemo1 {
public static void main(String[] args) {
//1.创建线程池对象
/**
* public ThreadPoolExecutor(int corePoolSize,
* int maximumPoolSize,
* long keepAliveTime,
* TimeUnit unit,
* BlockingQueue<Runnable> workQueue,
* ThreadFactory threadFactory,
* RejectedExecutionHandler handler)
*/
ExecutorService pool = new ThreadPoolExecutor(3,5,6, TimeUnit.SECONDS,new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
//给任务线程池处理
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();
}
}
MyRunnable任务类
package ThreadPool;
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "输出了:Hello world===>" + i);
}
try {
System.out.println(Thread.currentThread().getName() + "本任务与线程绑定了,线程进入休眠了~~~~");
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程池处理Callable任务
- 使用ExecutorService的方法
- Future submit(Callable command)
package ThreadPool;
import java.util.concurrent.*;
public class ThreadPoolDemo2 {
public static void main(String[] args) throws Exception {
//1.创建线程池对象
ExecutorService pool = new ThreadPoolExecutor(3,5,6, 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));
/*String s = f1.get();
System.out.println(s);*/
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
System.out.println(f4.get());
}
}
Callable任务类
package ThreadPool;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
private int n;
public MyCallable(int n){
this.n = n;
}
/**
* 重写call方法
* @return
* @throws Exception
*/
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
return Thread.currentThread().getName() + "线程执行1-"+n+"的结果是" + sum;
}
}
执行结果:
pool-1-thread-1线程执行1-100的结果是5050
pool-1-thread-2线程执行1-200的结果是20100
pool-1-thread-3线程执行1-300的结果是45150
pool-1-thread-3线程执行1-400的结果是80200