jdk源码解析--ThreadPoolExecutor类
Posted 我的IT技术路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk源码解析--ThreadPoolExecutor类相关的知识,希望对你有一定的参考价值。
在java中,线程池无论是在面试中或者是在实际使用中,都是一个高频出现问题,我们需要很好的了解和掌握java线程池。在了解这个线程池之前,我们先看下java中定义的几个关于线程池的类和它们的关系:Executor,Executors,ExecutorService,AbstractExecutorService和ThreadPoolExecutor。先看下类的继承关系图:
上面的图还是比较明显的看出这个类的关系:
Executor:该接口定义了向线程池提交任务执行的方法
ExecutorService:该接口继承Executor,并且丰富了线程池的其他操作,比如线程池的关闭,线程池允许有返回值的提交等
AbstractExecutorService:该抽象类是ExecutorService的一个实现类,该类中定义了一些具体的方法,该类中的一个常用方法是将execute方法封装成submit返回一个future对象,换句话说该方法允许线程带返回值。
ThreadPoolExecutor:这个类是真正线程池的实现类,它实现了AbstractExecutorService这个抽象类
Executors:该类是线程池的辅助类,里面提供了很多静态方法可以直接用来创建线程池,在jdk中,很多带s后缀的一般都是一个辅助类,比如arrays(数组辅助类),collections(集合辅助类),这些类里面会提供一些便捷的静态方法帮助大家实现类似的功能。
看完上面的类关系图之后,我们需要说明一下java线程池的工作原理(线程池的经典原理图):
这是线程池的经典原理图:
1. 当提交任务到线程池执行的时候,会先到核心线程开始执行
2. 如果核心线程满了会到阻塞队列进行排队,当核心线程完成当前任务时,会尝试从阻塞队列中获取待执行的任务
3. 当阻塞队列满了之后,会扩充线程数到最大线程数,执行当前任务
4. 当最大线程数满了之后,会进入拒绝策略,jdk提供了几种常用的拒绝策略,常用的是拒绝,拒绝最老的,以提交当前任务的线程执行该任务。
当我们了解了线程池的工作原理之后,我们可以尝试通过构建一个线程池,并且执行相应的任务,下面通过一个demo来说明一下线程池的简单使用。
1. import java.util.Random;
2. import java.util.concurrent.*;
3. import java.util.concurrent.atomic.AtomicInteger;
4. import java.util.concurrent.atomic.AtomicLong;
5. import java.util.stream.IntStream;
6.
7. public class TheadPoolTest {
8. public static final Random r = new Random();
9. public static void main(String[] args) {
10. ThreadFactory threadFactory = new ThreadFactory() {
11. final AtomicLong aLong = new AtomicLong(0);
12. @Override
13. public Thread newThread(Runnable r) {
14. Thread thread = new Thread(r);
15. thread.setDaemon(true);//设置守护线程
16. thread.setName("Test-Thread-"+aLong.incrementAndGet());//设置线程名
17. return thread;
18. }
19. };
20. AtomicInteger data =new AtomicInteger(0);
21. ThreadPoolExecutor executor = new ThreadPoolExecutor(
22. 5,//核心线程数
23. 10,//最大线程数
24. 10, TimeUnit.SECONDS,//线程空闲的最大等待时间
25. new ArrayBlockingQueue<>(100),//阻塞队列
26. threadFactory,//线程工程,一般线程工厂用来设置特定的线程名,设置是否是守护线程
27. new ThreadPoolExecutor.AbortPolicy()//拒绝策略
28. );
29. IntStream.range(0,10).forEach(i->{
30. Future<Boolean> future = executor.submit(new AddTask());
31. try {
32. if (future.get()){
33. data.incrementAndGet();
34. }
35. } catch (InterruptedException e) {
36. } catch (ExecutionException e) {
37. }
38. });
39. System.out.println("大于5的次数是:"+data.get());
40. }
41.
42. public static class AddTask implements Callable<Boolean>{
43.
44. @Override
45. public Boolean call() throws Exception {
46. int result = r.nextInt(10);
47. System.out.println(Thread.currentThread().getName()
48. +" get result is " +result);
49. return result>5;
50. }
51. }
52. }
上面使用代码比较简单,我们通过每个线程执行的返回值来判断每个线程的随机值是否大于5,最后统计出大于5的线程的个数。上面的例子我们使用了callable,而不是runnable,这两者的主要区别在于线程执行的返回值。我们看下最后的执行结果:
本节内容就先到这里,下节内容开始,我们会描述线程池的底层源码的实现。
以上是关于jdk源码解析--ThreadPoolExecutor类的主要内容,如果未能解决你的问题,请参考以下文章