Java中的线程池

一:什么是线程池

线程池就是用来管理和复用线程的工具,它可以减少线程的创建和销毁开销。

举个例子:

现有一个建筑公司,

它现在需要做一个A项目,该项目需要5个人,该项目需要招聘5个临时工来做这个工作,做完工作后结算工钱走人!

过了一段时间,

公司又做一个B项目,该项目需要8个人,那么该项目还需招聘8个临时来做这个工作,做完工作后结算工钱走人!

这样非常麻烦 >_>!!

因此现在就开辟了一个线程池,把5个临时工放入线程池中,让其变成了该公式的员工,其设置为核心线程池为5,即其核心工人为5;

之后如果项目需要的人多与5个,就再找临时工,如果需要的人少于5个就,从核心工人中选;

二:如何创建一个线程池

//创建一个线程池
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,factory,handler);

其中线程池中又7个参数,其中分别为:

核心线程数,最大线程数,保持存活的时间,设置时间的单位,阻塞队列,线程池中的线程工厂,拒绝策略处理器;

三:创建一个线程池,并用execute/submit方法执行任务

1.线程池的执行流程

第一步:创建线程池;

第二步:用execute方法执行任务

第三步:线程执行完毕后,线程并不会立即销毁,而是继续保持在池中等待下一个任务

第四步:当线程空闲时间超出指定时间,且当前线程数量大于核心线程数时,线程会被回收

2.例子(用execute方法执行任务

public static void main(String[] args) {
        //核心线程数
        int corePoolSize = 5;
        //最大线程数
        int maximumPoolSize = 10;
        //保持存活的时间 -- 刨除去核心线程数,不超过最大的线程数,其他多余的临时线程的存活时间为1s
        //也就是说,线程数超过核心的线程数,空闲的时间超过keepAliveTime,就会销毁非核心线程
        long keepAliveTime = 1;
        //设置时间的单位,为s
        TimeUnit unit =TimeUnit.SECONDS;
        //阻塞队列(现有线程数多余最大的线程数,就是多余的线程,就需要阻塞队列,让其等待)
        BlockingDeque<Runnable> workQueue =new LinkedBlockingDeque<>();
        //线程池中的线程工厂 -- 默认创建我们的线程
        ThreadFactory factory=Executors.defaultThreadFactory();
        //拒绝策略处理器  ,当超过线程池的最大线程数,并且,其阻塞队列也放不下的时候,会用拒绝策略处理器,进行拒绝
        ThreadPoolExecutor.AbortPolicy handler =new ThreadPoolExecutor.AbortPolicy();
        //创建一个线程池
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
                corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,factory,handler
                );

        //使用线程池
        for (int i = 0; i < 30; i++) {
            poolExecutor.execute(
                    ()->{
                        System.out.println("当前的线程为"+Thread.currentThread().getName()+"正在执行");
                    }
            );
        }
        poolExecutor.shutdown();
    }

运行结果:

3.例子(并用submit方法执行任务):

 public static void main(String[] args) {
        //核心线程数
        int corePoolSize = 5;
        //最大线程数
        int maximumPoolSize = 10;
        //保持存活的时间 -- 刨除去核心线程数,不超过最大的线程数,其他多余的临时线程的存活时间为1s
        //也就是说,线程数超过核心的线程数,空闲的时间超过keepAliveTime,就会销毁非核心线程
        long keepAliveTime = 1;
        //设置时间的单位,为s
        TimeUnit unit =TimeUnit.SECONDS;
        //阻塞队列(现有线程数多余最大的线程数,就是多余的线程,就需要阻塞队列,让其等待)
        BlockingDeque<Runnable> workQueue =new LinkedBlockingDeque<>();
        //线程池中的线程工厂 -- 默认创建我们的线程
        ThreadFactory factory=Executors.defaultThreadFactory();
        //拒绝策略处理器  ,当超过线程池的最大线程数,并且,其阻塞队列也放不下的时候,会用拒绝策略处理器,进行拒绝
        ThreadPoolExecutor.AbortPolicy handler =new ThreadPoolExecutor.AbortPolicy();
        //创建一个线程池
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
                corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,factory,handler
                );

        //使用线程池
        List<Object> f =new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            Future<?> future = poolExecutor.submit(
                    ()->{
                        String s = "当前的线程为" + Thread.currentThread().getName() + "正在执行";
                        System.out.println(s);
                        return s;
                    }
            );
            try {
                Object o = future.get();
                f.add(o);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }

        poolExecutor.shutdown();
        System.out.println("+++++++++++++++");
        System.out.println("f = " + f);
    }

运行结果

四:submit与execute的区别

execute 方法没有返回值,适用于不关心结果和异常的简单任务;

submit 有返回值,适用于需要获取结果或处理异常的场景。

五:线程池有几种阻塞队列

有5种

有界队列 ArrayBlockingQueue;

无界队列 LinkedBlockingQueue;

优先级队列 PriorityBlockingQueue;

延迟队列 DelayQueue;

同步队列 SynchronousQueue

1.ArrayBlockingQueue:一个先进先出的有界队列,底层是一个数组,一般大小固定的线程池都用它;

2.LinkedBlockingQueue:底层是一个链表,不指定大小,默认为Integer.MAX_VALUE,相当于一个无界队列;

3.PriorityBlockingQueue:一个支持优先级排序的无界队列;

4. DelayQueue:和优先级队列相似,是由二叉树实现的无界优先级阻塞队列;

5.SynchronousQueue:每一个插入操作必须等待一个线程移除操作,

任何一个移除操作必须等待另一个线程的插入操作;

六:线程池该如何关闭

可以调用线程池的shutdown或shutdownNow方法来关闭线程池。

1.shutdown 不会立即停止线程池,而是等待所有任务执行完毕后再关闭线程池

2.①shutdownNow 会尝试通过一系列动作来停止线程池,包括停止接收外部提交的任务、忽略队列里等待的任务、尝试将正在跑的任务 interrupt 中断;

②shutdownNow 不会真正终止正在运行的任务,只是给任务线程发送 interrupt 信号,任务是否能真正终止取决于线程是否响应 InterruptedException

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务