• 【业务功能篇91】微服务-springcloud-多线程-线程池执行顺序


    一、线程的实现方式

    1. 线程的实现方式

    1.1 继承Thread

    class ThreadDemo01 extends Thread{
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.2 实现Runnable接口

    class ThreadDemo02 implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.3 Callable接口

    class MyCallable implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程:" + Thread.currentThread().getName());
            return 10;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    public static void main(String[] args) throws ExecutionException, InterruptedException {
            System.out.println("main方法执行了...");
            ThreadDemo01 t1 = new ThreadDemo01();
            t1.start();
    
            ThreadDemo02 t2 = new ThreadDemo02();
            new Thread(t2).start();
            new Thread(()->{
                System.out.println("当前线程:" + Thread.currentThread().getName());
            }).start();
    
            // 通过Callable接口来实现  FutureTask 本质上是一个Runnable接口
            FutureTask futureTask = new FutureTask(new MyCallable());
            Thread t3 = new Thread(futureTask);
            t3.start();
            // 阻塞等待子线程的执行完成,然后获取线程的返回结果
            Object o = futureTask.get();
            System.out.println("o = " + o);
            System.out.println("main方法结束了...");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.线程池的实现

      上面的三种获取线程的方法是直接获取,没有对线程做相关的管理,这时可以通过线程池来更加高效的管理线程对象。

    // 定义一个线程池对象
        private static ExecutorService service = Executors.newFixedThreadPool(5);
    
    • 1
    • 2

    然后我们就可以通过这个线程池对象来获取对应的线程

            service.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程池--》当前线程:" + Thread.currentThread().getName());
                }
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3. 获取线程的区别

      通过上面的介绍我们发现获取线程的方式

    • 继承Thread对象
    • 实现Runnable接口
    • 实现Callable接口
    • 线程池

    继承Thread对象和实现Runnable接口没有办法获取返回结果的,实现Callable接口可以获取线程的返回结果。当然这三种方式都不能控制我们的资源,线程池可以控制资源。

    二、线程池的详解

    1.线程池的创建方式

    • 通过Executors的静态方法
    • 通过 new ThreadPoolExecutor方式创建

    七大参数的作用

    参数作用
    corePoolSize核心线程数,线程池创建好后就准备就绪的线程数量,一直存在
    maximumPoolSize最大线程数量,控制资源
    keepAliveTime存活时间,如果当前线程数量如果大于核心线程数量,释放空闲的线程,
    最大线程-核心数量
    unit时间单位
    BlockingQueue阻塞队列,如果任务很多,就会把多的任务放在队列中
    threadFactory线程的工厂
    handler如果队列满了,按照指定的拒绝策略执行任务
        /**
         * 线程池详解
         * @param args
         */
        public static void main(String[] args) {
            // 第一种获取的方式
            ExecutorService service = Executors.newFixedThreadPool(10);
            // 第二种方式: 直接new ThreadPoolExecutor()对象,并且手动的指定对应的参数
            // corePoolSize:线程池的核心线程数量 线程池创建出来后就会 new Thread() 5个
            // maximumPoolSize:最大的线程数量,线程池支持的最大的线程数
            // keepAliveTime:存活时间,当线程数大于核心线程,空闲的线程的存活时间 8-5=3
            // unit:存活时间的单位
            // BlockingQueue workQueue:阻塞队列 当线程数超过了核心线程数据,那么新的请求到来的时候会加入到阻塞的队列中
            // new LinkedBlockingQueue<>() 默认队列的长度是 Integer.MAX 那这个就太大了,所以我们需要指定队列的长度
            // threadFactory:创建线程的工厂对象
            // RejectedExecutionHandler handler:当线程数大于最大线程数的时候会执行的淘汰策略
            ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5
                    , 100
                    , 10
                    , TimeUnit.SECONDS
                    , new LinkedBlockingQueue<>(10000)
                    , Executors.defaultThreadFactory()
                    , new ThreadPoolExecutor.AbortPolicy()
            );
            poolExecutor.execute(()->{
                System.out.println("----->" + Thread.currentThread().getName());
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2.线程池的执行顺序

    线程池创建,准备好core数量的核心线程,准备接收任务

    image.png

    • 1.先判断核心线程是否已满,未满分配线程
    • 2.任务队列是否已满,未满放入队列
    • 3.是否达到最大的线程数量,未达到创建新的线程
    • 4.通过对应的reject指定的拒绝策略进行处理

    线程池的面试题:

    • 有一个线程池,core:5,max:50,queue:100,如果并发是200,那么线程池是怎么处理的?
    • 首先 200个中的前面5个会直接被核心线程处理,然后6个到105个会加入到阻塞队列中,然后106到155的请求在最大线程数中,那么会创建对应的线程来处理这些请求,之后剩下的45个请求会被直接放弃

    image.png

    3.线程池的好处

    • 降低资源消耗
    • 提高响应速度
    • 提高线程的管理
  • 相关阅读:
    二叉树与二叉搜索树的公共祖先 力扣 (Python)
    【JavaScript】文件分片上传
    【python】(十)python的错误与异常
    mongodb、mysql、redis 区别
    华为主题开发分享-在windows 11操作系统上识别不到P50等华为手机的解决方案
    el-checkbox-group限制勾选数量
    《深度探索C++对象模型》阅读笔记 第二章 构造函数语意学
    双碳目标下基于“遥感+”集成技术的碳储量、碳排放、碳循环、温室气体等多领域监测与模拟实践
    微信小程序剪切图片的功能
    微服务架构学习与思考
  • 原文地址:https://blog.csdn.net/studyday1/article/details/132610176