资讯 小学 初中 高中 语言 会计职称 学历提升 法考 计算机考试 医护考试 建工考试 教育百科
栏目分类:
子分类:
返回
空麓网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
空麓网 > 计算机考试 > 软件开发 > 后端开发 > Java

【多线程初阶五】线程池&&常考面试题

Java 更新时间: 发布时间: 计算机考试归档 最新发布

【多线程初阶五】线程池&&常考面试题

目录

🌟一、线程池

🌈1、线程池是什么?

🌈2、为什么要使用线程池?

🌈3、怎么使用线程池?

        1、使用标准库中的线程池(6种)——>不推荐使用。  

        2、自定义一个线程池(重点)


🌟一、线程池

🌈1、线程池是什么?

        简单理解就是:在线程池中已经存在了一些创建好的线程,只需要往线程池中提交任务即可,当任务被提交到线程池之后,任务就会被自动执行。当程序启动的时候,如果发现有任务就立刻执行,没有任务就阻塞等待。

🌈2、为什么要使用线程池?

        线程池最大的好处就是减少频繁创建和销毁线程的系统的开销,从而提高效率。


🌈3、怎么使用线程池?

        1、使用标准库中的线程池(6种)——>不推荐使用。  

        (1)6种方法     

public static void main(String[] args) {        // 1. 用来处理大量短时间工作任务的线程池,如果池中没有可用的线程将创建新的线程,如果线程空闲60秒将收回并移出缓存        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();        // 2. 创建一个操作无界队列且固定大小线程池        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);        // 3. 创建一个操作无界队列且只有一个工作线程的线程池        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();        // 4. 创建一个单线程执行器,可以在给定时间后执行或定期执行。        ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();        // 5. 创建一个指定大小的线程池,可以在给定时间后执行或定期执行。        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);        // 6. 创建一个指定大小(不传入参数,为当前机器CPU核心数)的线程池,并行地处理任务,不保证处理顺序        Executors.newWorkStealingPool();    }

  ❓面试题1:如何自定义线程池?  创建线程池时构造方法的参数及含义?(重点)

        (1)  通过工厂方法获取的线程池,最终都是ThreadPoolExecutor对象。通过创建(new)一个 ThreadPoolExecutor的对象自定义线程池。

        (2)参数含义

 1️⃣corePoolSize:核心线程数,创建线程池时包含的最小线程数量。(一次性全部创建完成)

 2️⃣maxminPoolSize:最大线程数。当线程不够用时,允许系统可以创建的最多线程数(最大线程数-核心线程数)。

 3️⃣keepAliveTime:临时线程空闲的时长。

 4️⃣Timeunit unit:空闲的时间单位和keepAliveTime一起使用。

 5️⃣BlockingQueue:存放任务的阻塞队列。

 6️⃣threadfactory:线程工厂,规定了怎么去创建线程。用系统默认的就行。

 7️⃣RejectedExecutionHander hander:拒绝策略,触发时机:当线程池处理不了过多的任务时。


理解上述过程:

🌰1:吃火锅~

(1)火锅店一共有10张桌子(对应核心线程数);

(2)中午2.00去,店里没有人,随便坐,此时店里的桌子足够招待客人;(对应:当任务量较小时,核心线程完全可以处理)

(3)到了下午5/6点,到饭点了,来吃饭的人逐渐增多,此时10张桌子就已经坐满了(对应:核心线程数已满);

(4)再来的顾客就要排号(对应:往阻塞队列里面添加任务)

(5)当顾客人数越来越多,老板就在店门口加了5张桌子(对应:创建的临时线程数)

(6)当顾客慢慢吃完了,也没有新来的排号的顾客时,门口的5张桌子就空闲下来了,说明店里的10张桌子完全可以处理顾客的人数;

(7)当老板等待30min后(对应:线程的空间时间和时间单位)仍然没有新来的顾客,门口的桌子用不上了,那就可以收回了(对应:回收临时线程)

(8)当在用餐高峰期,门口的桌子也用完了,那对于新来的顾客执行拒绝策略。


 上述过程总结:

 

❓面试题2:描述一下线程池的工作原理?(上述7个参数是如何搭配使用的?)(重点)

(1)当任务添加到线程池中,先判断当前任务数是否大于核心线程数;

(2)如果任务数小于等于核心线程数,则直接执行任务,否则加入阻塞队列中等待;

(3)当阻塞队列满了之后,按照指定的最大线程数创建临时线程(最大线程数-核心线程数);

(4)当阻塞队列满了之后,而且临时线程也已经创建完成,再次提交任务的时候,就会执行拒绝策略

(5)当任务量减少且核心线程数完全够执行,临时线程达到一定的空间时长之后就会被回收。

理解拒绝策略:

❓问题3:为什么不推荐使用系统自带的线程池?

❓ 面试题3:创建线程池的时候,指定的核心线程数一般是多少比较合适?

(1)这个没有一个准确的答案,要根据业务场景和计算机配置来决定;

(2)对于计算密集型的程序,那么线程数可以适当的增大;对于IO密集型的程序,取决于磁盘的读写效率,线程数过大也不会提高程序的效率;

(3)还需要考虑COU的核心数量是多少;

(4)最终要通过测试对比,来确定一个合适的线程数。

(2)演示使用JDK提供的方法实现线程池

(1)创建线程

(2)提交线程

        threadPool.submit();

//模拟实现线程池:一共有10个任务,线程池有3个线程。将任务提交到线程池,期望输出结果:每次这10个线程都是由线程池中的三个线程执行的。    public static void main(String[] args) throws InterruptedException {        //1、创建一个大小为3的线程池        ExecutorService threadPool = Executors.newFixedThreadPool(3);        //2、提交任务到线程池        for (int i = 0; i < 10; i++) {            int taskId = i;            //3、表示要执行的任务            threadPool.submit(()->{                System.out.println("正在执行任务"+taskId+","+Thread.currentThread().getName());            });        }        //4、等待任务执行        TimeUnit.SECONDS.sleep(5);        System.out.println("任务执行结束");    }

  2、自定义一个线程池(重点)

🍀 创建一个线程池需要满足的条件:

        (1)需要提交任务到线程池,那么就要有一种数据结构来保存我们提交的任务;(考虑用阻塞队列实现)

        (2)创建线程时需要指定初始线程数量,这些线程不停的扫描阻塞队列,一旦有任务就立刻执行。(可以考虑用线程池对象的构造方法,接收要创建线程的数据,并在构造方法中完成线程的创建)   

自定义实现线程池: 

public class a03_MyThreadPool {    //目标:用阻塞队列模拟线程池(创建一些线程表示线程池中已有的工作线程),往线程池中提交任务后,任务被工作线程执行    //1、定义一个阻塞队列(就代表线程池),初始化容量为3。--------不理解。注意类型为Runnable    BlockingQueue queue = new LinkedBlockingQueue<>(3);    //2、核心方法:对外提供一个方法,用来往线程池中提交任务    public void submit(Runnable task) throws InterruptedException {        queue.put(task);    }    //3、构造方法中,就要创建一些工作线程,让这些工作俩执行上述提交的任务    public a03_MyThreadPool(int capacity){        if(capacity <= 0){            throw new RuntimeException("线程池的数量不能小于0");        }        //4、在线程池中创建一些工作线程(创建的个数就是初始化线程池给定的容量数)        for (int i = 0; i < capacity; i++) {            Thread thread= new Thread(()->{                //5、不停的扫描                while (true){                    try {                        //6、取出提交的任务,并执行                        Runnable task = queue.take();                        task.run();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            });            //7、启动线程            thread.start();        }    }}

测试类:

public static void main(String[] args) throws InterruptedException {        //1、创建一个大小为3的线程池        a03_MyThreadPool threadPool = new a03_MyThreadPool(3);        //2、提交任务到线程池        for (int i = 0; i < 10; i++) {            int taskId = i;            //3、表示要执行的任务            threadPool.submit(()->{                System.out.println("正在执行任务"+taskId+","+Thread.currentThread().getName());            });        }        //4、等待任务执行        TimeUnit.SECONDS.sleep(5);        System.out.println("任务执行结束");    }

执行结果:


不要焦虑,行动解决焦虑!

转载请注明:文章转载自 http://www.konglu.com/
本文地址:http://www.konglu.com/it/1096325.html
免责声明:

我们致力于保护作者版权,注重分享,被刊用文章【【多线程初阶五】线程池&&常考面试题】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理,本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意,谢谢!

我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2023 成都空麓科技有限公司

ICP备案号:蜀ICP备2023000828号-2