目录
线程池的作用
线程池的使用
线程池的创建方式
线程池的解析
①Executors与ThreadPoolExecutor
②ThreadPoolExecutor线程池的构造方法
③RejectedExecutionHandler线程池的拒绝策略
固定线程数量线程池的简单模拟实现
对于线程的使用,可能会频繁的创建与销毁.
但对于这些创建与销毁来说,会产生比较大的开销.因为对于线程的创建与销毁来说,与底层的操作系统息息相关.而像进入操作系统的任务,会被称为"内核态".在内核态当中会执行其他任务,同时内核态中的操作也是我们不可控的,频繁的创建销毁线程需要的成本会更大.
对此,就有了线程池.创造了线程放入"池"中管理,并调用执行一定的任务.在任务完毕后,我们对其并不会进行销毁,而是将其放回到"池"中去.极大的减少了开销.
除了减少了资源的开销,还能对线程在"池"中进行管理.
总结:
在java标准库中,提供了我们使用线程池.
线程池比较特殊,不用去实例化一个类.而是调用了Executors的一个类方法(静态方法)newFixedThreadPool去创建线程池.
返回值为ExecutorService.
ExecutorService pool = Executors.newFixedThreadPool(10);//在线程池中创建10个线程
pool.submit(new Runnable() {//调用submit方法,给线程们布置任务执行
@Override
public void run() {
System.out.println("wow");
}
});
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("haha");
}
});
在Executors中线程池的创建大致分四种方法.
①newFixedThreadPool-创建固定线程数目的线程池
②newCachedThreadPool-创建线程数目动态增长的线程池
③newSingleThreadExecutor-创建单线程的线程池
④newScheduleThreadPool-创建可延迟执行命令的线程池(类似Timer)
上述对于线程池的创建的四种方法,其实本质上都是同一种方法:ThreadPoolExecutor.
Executors本质上只是对ThreadPoolExecutor类的封装.
源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
//在Exeucutors中实例化了一个ScheduledThreadPoolExecutor,这个类继承了ThreadPoolExecutor
可以看到都ThreadPoolExecutor这个类有关,Executors中不同种类的线程池只是在ThreadPoolExecutor传入的参数不同.
选择了要创建哪一种线程池,在Executor中会默认的帮你设定相应的参数.从而让我们更方便的使用.
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
在ThreadPoolExecutor类中,实现了四个拒绝策略
拒绝的是什么?什么时候会触发拒绝条件?
前面我们提到,通过调用创建Executors的实例化对象的submit方法将任务添加到阻塞队列当中.
当任务数量达到一定的数量,队列中塞满了或者线程池中的每一个线程都在工作没有多余的线程时会触发拒绝条件.
AbortPolicy-抛出一个RejectedExecutionException异常
CallRunsPolicy-将被拒绝的任务返回给提交任务的线程执行
DiscardOldestPolicy-抛弃阻塞队列中队首的任务,并把新任务添加进来
DiscardPolicy-抛弃这个想要新加入的任务
分为:
public class MyThreadPool extends Thread{
private BlockingQueue queue = new LinkedBlockingQueue<>();//阻塞队列存放任务
public MyThreadPool(int n){//构造方法,在创建线程池的时候就创建相应数量的线程
for(int i = 0; i < n; i++){
Thread thread = new Thread(() -> {
while(true){
try {
Runnable runnable = queue.take();
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
public void submit(Runnable runnable) throws InterruptedException {//将任务存放到阻塞队列的方法
queue.put(runnable);
}
public static void main(String[] args) throws InterruptedException {
MyThreadPool pool = new MyThreadPool(3);
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("wowo");
}
});
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("haha");
}
});
}
}