java并发编程(线程池的使用与原理)

线程池

引语(和线程池本身无关):

 java并发编程(线程池的使用与原理)

java并发编程(线程池的使用与原理)

java并发编程(线程池的使用与原理)

并没有对A中的方法做同步处理输出结果依然是500000,因为上面的5个任务其实是在主线程中串行执行的。

 

实际中,我们不会自己写一个类去实现Executor接口和接口里面的execute方法,因为那实在是太底层了。execute方法的实现是非常复杂的。Executor接口中execute方法的实现,java已经帮我们做好了,实现过程如下图:

java并发编程(线程池的使用与原理) 

注:读者在阅读时可以把文章中的“ThreadPoolExecutor”全部换成“线程池”来理解)

真正复杂实现execute方法的地方是ThreadPoolExecutor类,也就是我们真正意义上所说的线程池。对于线程池而言,我们可以粗略的想象一下它应该有的组成部件(池中里面应该有很多线程实例,另外应该有接收外界提交任务的接口,另外应该有暂存提交过来的任务的队列容器,另外应该有对队列中的任务的调度器)。所以ThreadPoolExecutor类对象才能调用execute方法(这个调用就不像上面的引语中那样简单粗暴的在主线程中串行执行execute接收的任务了,而是把接收到的Runnable任务放到线程池对象维护的任务等待队列中排队,由线程池的任务调度器从队列中按照某种调度算法取出任务,分配线程实例执行任务)。该类有2000多行实现代码。里面封装了上面我们粗略想象的那些部件们。execute方法就是接收外界提交任务的接口(此外还有submit方法,后面再讨论这个方法),从而可以把execute方法接收到了Runnable任务交给池子中的线程们去执行。

在以上继承关系之外有Executors类,它不继承自任何类,里面主要封装了几个用于创建ThreadPoolExecutor类对象的静态方法(即创建一个实实在在的线程池对象),这些方法只是简单地调用ThreadPoolExecutor类的构造函数,没有技术含量。并且这些方法返回的并不是ThreadPoolExecutor对象的引用,而是ExecutorService的引用(接口的引用可以引用实现了该接口的子类对象)。如果不乐意使用Executors中的静态方法来创建ThreadPoolExecutor对象的话,可以自己直接调用ThreadPoolExecutor类的构造方法来创建六大线程池以外的线程池。(六大线程池是指Executors类中已经封装的6个静态方法对应创建的线程池,后面再讲,先不要深究)

不管是六大线程池还是我们自己直接调用ThreadPoolExecutor类的构造方法创建的线程池,都可以使用ExecutorService接口中的方法,因为正如上面的继承关系图所示,ThreadPoolExecutor类实现了ExecutorService接口(子类实现了某个接口,那么必须实现接口中的所有方法)。所以通常情况下我们用ExecutorService接口的引用来引用线程池对象。ExecutorService接口中定义的方法如下:

java并发编程(线程池的使用与原理) 

本文我们通过源码注释的形式说明ExecutorService接口中部分方法的功能。

 java并发编程(线程池的使用与原理)

java并发编程(线程池的使用与原理)

java并发编程(线程池的使用与原理)

自此,我们大致明白了线程池的原理(最上面的继承关系图)和对外开放的方法ExecutorService中定义的那些),以及如何创建线程池Executors中定义的六大静态方法或者自己直接调用ThreadPoolExecutor类的构造方法),如何使用和管理线程池ExecutorService中定义的那些)。另一篇文章中我们再来详细讲解使用Executors中定义的六大静态方法创建六大线程池。