java六种线程池
六大线程池
本文讲述之前我们提到的Executors类(注意加了s的)中的六个静态方法,分别创建六种不同的线程池对象。之前我们已经提到,ThreadPoolExecutor类的别称就是线程池。它是继承自Executor接口(注意没有s)。继承关系图如下。
六大静态方法创建的ThreadPoolExecutor对象,返回的父接口的引用,即返回的ExecutorService的引用。六大静态方法内部都是直接或间接调用ThreadPoolExecutor类的构造方法创建线程池对象,这六个静态方法本身是没有技术含量的。其中一个静态方法的源码如下,其他5个也类似。
①:FixedThreadPool,特点:固定池子中线程的个数。使用静态方法newFixedThreadPool()创建线程池的时候指定线程池个数。示例如下:
输出如下:
②:CachedThreadPool(弹性缓存线程池),特点:用newCachedThreadPool()方法创建该线程池对象,创建之初里面一个线程都没有,当execute方法或submit方法向线程池提交任务时,会自动新建线程;如果线程池中有空余线程,则不会新建;这种线程池一般最多情况可以容纳几万个线程,里面的线程空余60s会被回收。创建示例:
③:SingleThreadPool(单线程线程池),特点:池中只有一个线程,如果扔5个任务进来,那么有4个任务将排队;作用是保证任务的顺序执行。创建示例:
④:ScheduledThreadpool(定时器线程池),这种线程池的创建,对应的静态方法为:
返回的不再是ExecutorService接口的引用了,但是我们依然可以用ExecutorService接口的引用去引用这种线程池对象。因为返回的是ScheduledExecutorService接口的引用,这个接口也是继承自ExecutorService接口,源码如下:
同时我们看到在newScheduledThreadPool方法中也不再是调用ThreadPoolExecutor类的构造方法,而是调的ScheduledThreadPoolExecutor这个方法,这个方法是ScheduledThreadPoolExecutor类的构造方法。这个类和之前我们提到的线程池类的(继承)关系如下:
在子类ScheduledThreadPoolExecutor构造方法中是直接调用的父类构造方法,于是归根结底还是调用的ThreadPoolExecutor类的构造方法。
整理上面几个接口和类的关系如下:
源码中ScheduledThreadPoolExecutor类的定义如下:
由上面整理的继承关系图可知,我们使用那三个接口的引用去引用这种线程池对象都是可以的(但是在使用时,切记只能用下面的第三种引用方式,因为虽然创建的是ScheduledThreadPoolExecutor对象,但如果用Executor去引用,就只能调用Executor接口中定义的方法;如果用ExecutorService接口去引用,就只能调用ExecutorService接口中定义的方法,无法使用ScheduledExecutorService接口中新增的方法,那么也就失去了这种线程池的意义),在idea中演示如下:
自此,我们明白了这种线程池和之前提到的接口和之前使用的线程池的关系,以及这种线程池的创建和引用方法。
接下来我们讲述这种线程池的使用方法,主要是使用ScheduledExecutorService接口中新增的方法。例如cheduleAtFixedRate()方法,方法签名如下:
接收4个参数,从形参名我们应该就能猜出来四个参数的含义了。第一个参数:接收一个Runnable任务。第二个参数:初始延迟时间,任务提交到线程池后延迟这么多时间才开始执行,如果设为0,那就是任务提交过来就开始执行了。第三个参数:这个任务会每隔这么多时间重新执行一次。第四个参数:为前两个参数的单位。使用示例如下:
除了cheduleAtFixedRate()方法,还有scheduleWithFixedDelay()方法和schedule()方法。本文不再赘述,在此基础上,读者可以查看源码注释。
下面这两种线程池,等我升级了jdk再给大家分享。
⑤WorkStealingPool
⑥ForkJoinPool