Java线程与线程池ThreadPoolExecutor,Executors解析

Posted lovoo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java线程与线程池ThreadPoolExecutor,Executors解析相关的知识,希望对你有一定的参考价值。

参考:https://blog.csdn.net/tony_java_2017/article/details/81275908

1、初始化线程的 4 种方式

1)、继承 Thread
2)、实现 Runnable 接口
3)、实现 Callable 接口 + FutureTask (可以拿到返回结果,可以处理异常)
4)、线程池
方式 1 和方式 2:主进程无法获取线程的运算结果。不适合当前场景
方式 3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可以导致 服务器资源耗尽。
方式 4:通过如下两种方式初始化线程池

 Executors.newFiexedThreadPool(3); 
 //或者 new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit unit, workQueue, threadFactory, handler);

通过线程池性能稳定,也可以获取执行结果,并捕获异常。但是,在业务复杂情况下,一 个异步调用可能会依赖于另一个异步调用的执行结果。

全部测试代码:

public static ExecutorService service = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        Runable01 runable01 = new Runable01();
//        new Thread(runable01).start();

//        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
//        new Thread(futureTask).start();
//        System.out.println(futureTask.get() + "");

        //使用线程池
        Future<?> future = service.submit(new Callable01());
        System.out.println(future.get());

        /**
         * int corePoolSize, 核心线程数,空闲也不消失
         * int maximumPoolSize, 最大线程数
         * long keepAliveTime, (maximumPoolSize-corePoolSize)的存活时间
         * TimeUnit unit, 时间队列
         * BlockingQueue<Runnable> workQueue, 阻塞队列,存活任务,有空闲时到此队列取任务运行
         * ThreadFactory threadFactory, 线程工厂
         * RejectedExecutionHandler handler 队列满了,按照拒绝策略拒绝执行任务
         *
         * 一个线程池 core 7, max 20 , queue 50, 100个线程并发进来如何处理?
         * 首先7个进入core执行,50个进queue,13个进入max执行,多余的30使用拒绝策略丢弃
         */
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
                100,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

    }

    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            System.out.println("结果:" + 10 / 2);
        }
    }

    public static class Runable01 implements Runnable {
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            System.out.println("结果:" + 10 / 2);
        }
    }

    public static class Callable01 implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            Integer i = 10 / 2;
            System.out.println("结果:" + i);
            return i;
        }
    }

2、线程池的七大参数

@param corePoolSize 池中一直保持的线程的数量,即使线程空闲。除非设置了 allowCoreThreadTimeOut *
@param maximumPoolSize 池中允许的最大的线程数 *
@param keepAliveTime 当线程数大于核心线程数的时候,线程在最大多长时间没有接到新任务就会终止释放, 最终线程池维持在 corePoolSize 大小 *
@param unit 时间单位 *
@param workQueue 阻塞队列,用来存储等待执行的任务,如果当前对线程的需求超过了 corePoolSize 大小,就会放在这里等待空闲线程执行。
@param threadFactory 创建线程的工厂,比如指定线程名等
@param handler 拒绝策略,如果线程满了,线程池就会使用拒绝策略

ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
                100,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

运行流程:
1、线程池创建,准备好 core 数量的核心线程,准备接受任务
2、新的任务进来,用 core 准备好的空闲线程执行
(1) 、core 满了,就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队 列获取任务执行
(2) 、阻塞队列满了,就直接开新线程执行,最大只能开到 max 指定的数量
(3) 、max 都执行好了。Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自 动销毁。最终保持到 core 大小
(4) 、如果线程数开到了 max 的数量,还有新任务进来,就会使用 reject 指定的拒绝策 略进行处理 3、所有的线程创建都是由指定的 factory 创建的。
3、所有的线程创建都是由指定的 factory 创建的。

## 面试:

**一个线程池 core 7; max 20 ,queue:50,100 并发进来怎么分配的;**
 先有 7 个能直接得到执行,接下来 50 个进入队列排队,在多开 13 个继续执行。现在 70 个 被安排上了。剩下 30 个默认拒绝策略。

3、常见的 4 种线程池

3.1)newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若 无可回收,则新建线程。
3.2)newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3.3)newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。
3.4)newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务 按照指定顺序(FIFO, LIFO, 优先级)执行。

4、开发中为什么使用线程池

4.1)降低资源的消耗
 通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
4.2) 提高响应速度
 因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务 的状态,当任务来时无需创建新的线程就能执行
4.3) 提高线程的可管理性
 线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来 的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使 用线程池进行统一分配

以上是关于Java线程与线程池ThreadPoolExecutor,Executors解析的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程与并发库高级应用-线程池

Java多线程与并发——线程生命周期和线程池

Java 线程池和多线程编程 ——线程池理解与创建

java线程池和五种常用线程池的策略使用与解析

java线程池与五种常用线程池策略使用与解析

Java入门3.2---线程池