线程池粗略解析

我们先来看看使用。

事前准备:


public class FixedThreadPoolTest extends Thread{
   
@Override
   
public void run() {
       
System.out.println("我是运行在newFixedThreadPool线程池中的");
    }
}

其他的三个以此类推,这里就不在重复给出了。

package com.lqy.Multithreading.threadpool;



//线程池



import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;



/*

JAVA中有四种线程池,分别是:

以下是粗略又不负责的概括,具体的话建议去看一下我接下来的注释

newSingleThreadExecutor:单例线程池,该线程池中只会有一个线程处于运行状态,也就是说,如果用该线程池运行线程

        只会派出一个线程来运行,如果在运行过程中因为某些原因任务每完成但是线程不在了,就会在派出一个新的线程继续执行

        直到任务执行完毕

newCacheThreadPool:该线程池中线程的大小是没有上限的,除非是你内存爆了,否则你一直使用该线程池的话就会一直创建线程

newFixedThreadPool:在你创建的时候固定了某个值,这个值就是线程池中的最大线程数量,过了这个数量任务就会进入任务队列中等待

newScheduledThreaadPool:和newFixedThreadPool一样,但是它可以定时执行

 */

public class ThreadPoolImpl {

    private static ExecutorService singleThreadExecutor= Executors.newSingleThreadExecutor();

    private static ExecutorService cachedThreadPool=Executors.newCachedThreadPool();

    private static ExecutorService fixedThreadPool=Executors.newFixedThreadPool(3);

    private static ExecutorService scheduledExecutorService=Executors.newScheduledThreadPool(2);



    public static void main(String[] args) {

        CacheThreadPoolTest cacheThreadPoolTest=new CacheThreadPoolTest();

        FixedThreadPoolTest fixedThreadPoolTest=new FixedThreadPoolTest();

        ScheduledThreadPoolTest scheduledThreadPoolTest=new ScheduledThreadPoolTest();

        SingleThreadExecutorTest singleThreadExecutorTest=new SingleThreadExecutorTest();

        //注意,使用线程池运行线程有两种方法:submitexecute,其中submit可以获取返回值

        cachedThreadPool.execute(cacheThreadPoolTest);

        fixedThreadPool.execute(fixedThreadPoolTest);

        scheduledExecutorService.execute(scheduledThreadPoolTest);

        singleThreadExecutor.execute(singleThreadExecutorTest);

    }

}

运行结果:

 

知道了基本的用法后,我们来详细的了解一下吧。

我们首先来看一下ExecutorService类,通过查看源码可以发现,该类继承了Executor类,即:

所以我们先来看看Executor类:

Executor类是一个接口,里面只定义了一个execute方法:

于是我们接着看ExecutorService类,它也是一个接口,定义了更多的关于线程池的说法,可以说ExecutorService是所有线程池要实现的接口。

由于ExecutorService接口除了自己在定义的一些方法,还继承了Executor接口的execute方法,所以总的来说,如果需要创建新的线程池的话,就需要实现ExecutorService接口,也就是要实现如下方法:

 

通过查询我们可以知道,实现了ExecutorService接口的类有:

 

这些我们结合接下来的Executors类来看。

接下来我们看一下Executors类,通过查看源码和官方文档,我们知道它其实是一个工具类,也可以理解为是一个工厂方法,即调用不同的方法就返回不同的线程池。

我们来看一下newFixedThreadPool方法:

接下来我们看看它是怎么执行的,或者说,真正的构造出newFixedThreadPool对象的ThreadPoolExecutor类中都有什么方法。

通过查看源码我们可以发现ThreadPoolExecutor类继承了AbstractExecutorService类,记得我上面说过的嘛,线程池的实现一般有继承ExecutorService接口并实现其中的方法,我们查看AbstractExecutorService类就可以发现这个抽象类继承了ExecutorService接口,也就是说,最终ThreadPoolExecutor间接继承了ExecutorService接口。

总的关系就是:

Executors类中创建newFixedThreadPool其实是创建了ThreadPoolExecutor对象,然后

ThreadPoolExecutor extends AbstractExecutorService

AbstractExecutorService implements ExecutorService

ExecutorService我们一开始看过了,就是一个接口,实现线程池的总父接口(规范),所以我们现在来看AbstractExecutorService类(是一个抽象类)。

我们首先来看一下submit方法,通过源码可以发现其实是调用了execute方法。

 

我们接下来看看invokeAny方法。 

最后我们来看看invokeAll方法

 

也就是说,最终AbstractExecutorService实现了submit,invokeAnybody和invokeAll方法。

看完这两个类后,我们最终回到ThreadPoolExecutor类中。

我们来看看ThreadPoolExecutor类中的跟线程池有关的一些方法。

看完了ThreadPoolExecutor类,我们对于newFixedThreadPool方法也就有了了解,因为利用newFixedThreadPool方法创建出来的线程池就是固定的ThreadPoolExecutor类的对象。

我们接下来看看newSingleThreadExecutor方法。

则:

可以发现,它其实和newFixedThreadPool方法一样是创建了ThreadPoolExecutor类的对象。

但是不同的是,这个方法的核心线程数量为1,允许的最大线程数量也为1 .

之后我们再去看newCacheThreadPool方法,发现和上面两个方法一样,都是创建了ThreadPoolExecutor类的对象,不过它的核心线程数量为0,允许的最大线程数为Integer.MAX。

不过注意:不同于newFixedThreadPool和newSingleThreadExecutor方法,前面两个方法的任务等待队列是LinkedBlockQueue,newCacheThreadPool方法的任务等待队列是SynchronousQueue。

关于SynchronousQueue的解释可以看这篇文章:不存储元素的阻塞队列SynchronousQueue (baidu.com)

我们最后来看一下newScheduledThreadPool方法,它是新的线程池对象的创建。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
   
return new ScheduledThreadPoolExecutor(corePoolSize);
}

我们进入ScheduledThreadPoolExecutor类中看看:

首先看一下该类的继承关系:

 

接下来我们来看看这个类可供我们使用的构造方法。(注意到我说的是可供我们使用了嘛,意思就是说,除了用public关键字修饰的方法或变量,其他的我们其实都不是在自己的类中能调用的,我们解析源码的时候也应该注意这点

 

通过构造函数我们发现,它最终还是调用的ThreadPoolExecutor类的构造方法创建的线程池。

接下来我们来看看这个类中的一些方法:

 

对一些方法的使用:

/*
JAVA中有四种线程池,分别是:
以下是粗略又不负责的概括,具体的话建议去看一下我接下来的注释
newSingleThreadExecutor:单例线程池,该线程池中只会有一个线程处于运行状态,也就是说,如果用该线程池运行线程
        只会派出一个线程来运行,如果在运行过程中因为某些原因任务每完成但是线程不在了,就会在派出一个新的线程继续执行
        直到任务执行完毕
newCacheThreadPool:该线程池中线程的大小是没有上限的,除非是你内存爆了,否则你一直使用该线程池的话就会一直创建线程
newFixedThreadPool:在你创建的时候固定了某个值,这个值就是线程池中的最大线程数量,过了这个数量任务就会进入任务队列中等待
newScheduledThreaadPool:和newFixedThreadPool一样,但是它可以定时执行
 */
public class ThreadPoolImpl {
    private static ExecutorService singleThreadExecutor= Executors.newSingleThreadExecutor();
    private static ExecutorService cachedThreadPool=Executors.newCachedThreadPool();
    private static ExecutorService fixedThreadPool=Executors.newFixedThreadPool(3);
    private static ScheduledExecutorService scheduledExecutorService=Executors.newScheduledThreadPool(2);

    Map<String,String> map=new HashMap<>();
    public static void main(String[] args) {
        CacheThreadPoolTest cacheThreadPoolTest=new CacheThreadPoolTest();
        FixedThreadPoolTest fixedThreadPoolTest=new FixedThreadPoolTest();
        ScheduledThreadPoolTest scheduledThreadPoolTest=new ScheduledThreadPoolTest();
        SingleThreadExecutorTest singleThreadExecutorTest=new SingleThreadExecutorTest();
        //注意,使用线程池运行线程有两种方法:submit和execute,其中submit可以获取返回值
        /*cachedThreadPool.execute(cacheThreadPoolTest);
        fixedThreadPool.execute(fixedThreadPoolTest);
        scheduledExecutorService.execute(scheduledThreadPoolTest);
        singleThreadExecutor.execute(singleThreadExecutorTest);*/
        /*//如果你不将前面的线程执行注释掉就运行下面的代码的话,会发现一些有意思的事情,比如,JVM调优中代码顺序的改变
        System.out.println("测试schedule方法");
        System.out.println("10秒后执行");
        scheduledExecutorService.schedule(scheduledThreadPoolTest,10, TimeUnit.SECONDS);*/
        /*//测试返回值
        System.out.println("schedule方法的返回值");
        ScheduledFuture future=scheduledExecutorService.schedule(scheduledThreadPoolTest,3,TimeUnit.SECONDS);
        //通过运行我们可以发现,它其实是没有重写ToString方法的,它的返回值其实是对这个任务的一个介绍,里面封装的有
        //关于这个任务的一些信息,比如是那个任务以及等待时间
        System.out.println(future);*/
        //测试scheduleAtFixedRate方法
        System.out.println("测试scheduleAtFixedRate方法");
        scheduledExecutorService.scheduleAtFixedRate(scheduledThreadPoolTest,3,3,TimeUnit.SECONDS);
    }
}

通过查看源码我们可以发现,其实ScheduledThreadPoolExecutor类看似是一个新的实现类,但是其实继承了ThreadPoolExecutor类,很多方法也是调用了这个类的方法。

ScheduledThreadPoolExecutor主要是schedule类似的方法(延迟执行以及延迟循环执行)的实现。

所以,虽然我们看似是创建了四种不同的线程池,但是最终其实都是ThreadPoolExecutor类的对象,而在ThreadPoolExecutor类中,运行线程的方法在AbstractExecutorService抽象类中实现了。

有没有发现……

设计模式……

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值