当前位置:首页 > 科技  > 软件

说一下线程池的核心参数,线程池的执行原理

来源: 责编: 时间:2023-11-30 09:28:42 161观看
导读1.线程池的核心参数线程池七大核心参数如下所示:public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable>

1.线程池的核心参数

线程池七大核心参数如下所示:L5J28资讯网——每日最新资讯28at.com

public ThreadPoolExecutor(int corePoolSize,        int maximumPoolSize,         long keepAliveTime,         TimeUnit unit,         BlockingQueue<Runnable> workQueue,        ThreadFactory threadFactory,        RejectedExecutionHandler handler        )
  • corePoolSize: 核心线程数目
  • maximumPoolSize: 最大线程数目 = (核心线程+救急线程的最大数目)
  • keepAliveTime: 生存时间 - 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放
  • unit: 时间单位 , 救急线程的生存时间单位,如秒、毫秒等
  • workQueue: 当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务
  • **threadFactory: 线程工厂 , 可以定制线程对象的创建,例如设置线程名字、是否是守护线程等
  • handler 拒绝策略 - 当所有线程都在繁忙,workQueue 也放满时,会触发拒绝策略

思考:线程池的执行原理知道嘛?

2. 线程池的执行原理

1: 任务在提交的时候,首先判断核心线程数是否已满,如果没有满则直接添加到工作线程执行L5J28资讯网——每日最新资讯28at.com

2: 如果核心线程数满了,则判断阻塞队列是否已满,如果没有满,当前任务存入阻塞队列L5J28资讯网——每日最新资讯28at.com

3:如果阻塞队列也满了,则判断线程数是否小于最大线程数,如果满足条件,则使用临时线程执行任务如果核心或临时线程执行完成任务后会检查阻塞队列中是否有需要执行的线程,如果有,则使用非核心线程执行任务L5J28资讯网——每日最新资讯28at.com

4:如果所有线程都在忙着(核心线程+临时线程),则走拒绝策略L5J28资讯网——每日最新资讯28at.com

L5J28资讯网——每日最新资讯28at.com

思考:拒绝策略有哪些?

1.AbortPolicy:直接抛出异常,默认策略L5J28资讯网——每日最新资讯28at.com

2.CallerRunsPolicy:用调用者所在的线程来执行任务L5J28资讯网——每日最新资讯28at.com

3.DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务L5J28资讯网——每日最新资讯28at.com

4.DiscardPolicy:直接丢弃任务L5J28资讯网——每日最新资讯28at.com

案例:L5J28资讯网——每日最新资讯28at.com

public class TestThreadPoolExecutor {    static class MyTask implements Runnable {        private final String name;        private final long duration;        public MyTask(String name) {            this(name, 0);        }        public MyTask(String name, long duration) {            this.name = name;            this.duration = duration;        }        @Override        public void run() {            try {                LoggerUtils.get("myThread").debug("running..." + this);                Thread.sleep(duration);            } catch (InterruptedException e) {                e.printStackTrace();            }        }        @Override        public String toString() {            return "MyTask(" + name + ")";        }    }    public static void main(String[] args) throws InterruptedException {        AtomicInteger c = new AtomicInteger(1);        ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(                2,                3,                0,                TimeUnit.MILLISECONDS,                queue,                r -> new Thread(r, "myThread" + c.getAndIncrement()),                new ThreadPoolExecutor.AbortPolicy());        showState(queue, threadPool);        threadPool.submit(new MyTask("1", 3600000));        showState(queue, threadPool);        threadPool.submit(new MyTask("2", 3600000));        showState(queue, threadPool);        threadPool.submit(new MyTask("3"));        showState(queue, threadPool);        threadPool.submit(new MyTask("4"));        showState(queue, threadPool);        threadPool.submit(new MyTask("5",3600000));        showState(queue, threadPool);        threadPool.submit(new MyTask("6"));        showState(queue, threadPool);    }    private static void showState(ArrayBlockingQueue<Runnable> queue, ThreadPoolExecutor threadPool) {        try {            Thread.sleep(300);        } catch (InterruptedException e) {            e.printStackTrace();        }        List<Object> tasks = new ArrayList<>();        for (Runnable runnable : queue) {            try {                Field callable = FutureTask.class.getDeclaredField("callable");                callable.setAccessible(true);                Object adapter = callable.get(runnable);                Class<?> clazz = Class.forName("java.util.concurrent.Executors$RunnableAdapter");                Field task = clazz.getDeclaredField("task");                task.setAccessible(true);                Object o = task.get(adapter);                tasks.add(o);            } catch (Exception e) {                e.printStackTrace();            }        }        LoggerUtils.main.debug("pool size: {}, queue: {}", threadPool.getPoolSize(), tasks);    }}

思考:线程池中有哪些常见的阻塞队列?

3. 常见阻塞队列

workQueue: 当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务。L5J28资讯网——每日最新资讯28at.com

比较常见的有4个,用的最多是ArrayBlockingQueue和LinkedBlockingQueue。L5J28资讯网——每日最新资讯28at.com

  • 1.ArrayBlockingQueue:基于数组结构的有界阻塞队列
  • 2.LinkedBlockingQueue:基于链表结构的有界阻塞队列
  • 3.DelayedWorkQueue :是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前的
  • 4.SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作

3.1. ArrayBlockingQueue的LinkedBlockingQueue区别

inkedBlockingQueue**L5J28资讯网——每日最新资讯28at.com

ArrayBlockingQueueL5J28资讯网——每日最新资讯28at.com

默认无界,支持有界L5J28资讯网——每日最新资讯28at.com

强制有界L5J28资讯网——每日最新资讯28at.com

底层是链表L5J28资讯网——每日最新资讯28at.com

底层是数组L5J28资讯网——每日最新资讯28at.com

是懒惰的,创建节点的时候添加数据L5J28资讯网——每日最新资讯28at.com

提前初始化 Node  数组L5J28资讯网——每日最新资讯28at.com

入队会生成新 NodeL5J28资讯网——每日最新资讯28at.com

Node需要是提前创建好的L5J28资讯网——每日最新资讯28at.com

两把锁(头尾)L5J28资讯网——每日最新资讯28at.com

一把锁L5J28资讯网——每日最新资讯28at.com

左边是LinkedBlockingQueue加锁的方式,右边是ArrayBlockingQueue加锁的方式L5J28资讯网——每日最新资讯28at.com

L5J28资讯网——每日最新资讯28at.com

  • LinkedBlockingQueue:读和写各有一把锁,性能相对较好
  • ArrayBlockingQueue:只有一把锁,读和写公用,性能相对于LinkedBlockingQueue差一些

4. 线程池的种类有哪些

在java.util.concurrent.Executors类中提供了大量创建连接池的静态方法,常见就有四种L5J28资讯网——每日最新资讯28at.com

1.创建使用固定线程数的线程池L5J28资讯网——每日最新资讯28at.com

public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads,                                       0L,                                       TimeUnit.MILLISECONDS,                                       new LinkedBlockingQueue<>());    }
  • 核心线程数与最大线程数一样,没有救急线程
  • 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE
  • 适用场景:适用于任务量已知,相对耗时的任务
  • 案例
/** * @author springboot葵花宝典 * @description: TODO */public class FixedThreadPoolTest {    static class FixedThreadDemo implements Runnable{        @Override        public void run() {            String name = Thread.currentThread().getName();            for (int i = 0; i < 2; i++) {                System.out.println(name + ":" + i);            }        }    }    public static void main(String[] args) throws InterruptedException {        //创建一个固定大小的线程池,核心线程数和最大线程数都是3        ExecutorService executorService = Executors.newFixedThreadPool(3);        for (int i = 0; i < 5; i++) {            executorService.submit(new FixedThreadDemo());            Thread.sleep(10);        }        executorService.shutdown();    }}

2.单线程化的线程池,它只会用唯一的工作线程来执行任 务,保证所有任务按照指定顺序(FIFO)执行L5J28资讯网——每日最新资讯28at.com

public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService        (new ThreadPoolExecutor(1,         1,         0L,        TimeUnit.MILLISECONDS,         new LinkedBlockingQueue<>()));    }
  • 核心线程数和最大线程数都是1
  • 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE
  • 适用场景:适用于按照顺序执行的任务
  • 案例
/** * @author springboot葵花宝典 * @description: TODO */public class NewSingleThreadTest {    static int count = 0;    static class Demo implements Runnable {        @Override        public void run() {            count++;            System.out.println(Thread.currentThread().getName() + ":" + count);        }    }    public static void main(String[] args) throws InterruptedException {        //单个线程池,核心线程数和最大线程数都是1        ExecutorService exec = Executors.newSingleThreadExecutor();        for (int i = 0; i < 10; i++) {            exec.execute(new Demo());            Thread.sleep(5);        }        exec.shutdown();    }}
  1. 可缓存线程池
public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0,                                    Integer.MAX_VALUE,                                     60L,                                    TimeUnit.SECONDS, n                                    ew SynchronousQueue<>());    }
  • 核心线程数为0
  • 最大线程数是Integer.MAX_VALUE
  • 阻塞队列为SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作
  • 适用场景:适合任务数比较密集,但每个任务执行时间较短的情况
  • 案例:
/** * @author springboot葵花宝典 * @description: TODO */public class CachedThreadPoolTest {    static class Demo implements Runnable {        @Override        public void run() {            String name = Thread.currentThread().getName();            try {                //修改睡眠时间,模拟线程执行需要花费的时间                Thread.sleep(100);                System.out.println(name + "执行完了");            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) throws InterruptedException {        //创建一个缓存的线程,没有核心线程数,最大线程数为Integer.MAX_VALUE        ExecutorService exec = Executors.newCachedThreadPool();        for (int i = 0; i < 10; i++) {            exec.execute(new Demo());            Thread.sleep(1);        }        exec.shutdown();    }}

4.提供了“延迟”和“周期执行”功能的ThreadPoolExecutor

public ScheduledThreadPoolExecutor(int corePoolSize,                                   ThreadFactory threadFactory,                                   RejectedExecutionHandler handler{ super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory, handler);                     }
  • 适用场景:有定时和延迟执行的任务
  • 案例
/** * @author springboot葵花宝典 * @description: TODO */public class ScheduledThreadPoolTest {    static class Task implements Runnable {        @Override        public void run() {            try {                String name = Thread.currentThread().getName();                System.out.println(name + ", 开始:" + new Date());                Thread.sleep(1000);                System.out.println(name + ", 结束:" + new Date());            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) throws InterruptedException {        //按照周期执行的线程池,核心线程数为2,最大线程数为Integer.MAX_VALUE        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);        System.out.println("程序开始:" + new Date());        /**         * schedule 提交任务到线程池中         * 第一个参数:提交的任务         * 第二个参数:任务执行的延迟时间         * 第三个参数:时间单位         */        scheduledThreadPool.schedule(new Task(), 0, TimeUnit.SECONDS);        scheduledThreadPool.schedule(new Task(), 1, TimeUnit.SECONDS);        scheduledThreadPool.schedule(new Task(), 5, TimeUnit.SECONDS);        Thread.sleep(5000);        // 关闭线程池        scheduledThreadPool.shutdown();    }}

5. 线程池面试题

面试官:线程池的核心参数有哪些?

候选人:L5J28资讯网——每日最新资讯28at.com

在线程池中一共有7个核心参数:L5J28资讯网——每日最新资讯28at.com

  1. corePoolSize 核心线程数目 - 池中会保留的最多线程数
  2. maximumPoolSize 最大线程数目 - 核心线程+救急线程的最大数目
  3. keepAliveTime 生存时间 - 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放
  4. unit 时间单位 - 救急线程的生存时间单位,如秒、毫秒等
  5. workQueue - 当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务
  6. threadFactory 线程工厂 - 可以定制线程对象的创建,例如设置线程名字、是否是守护线程等
  7. handler 拒绝策略 - 当所有线程都在繁忙,workQueue 也放满时,会触发拒绝策略

在拒绝策略中又有4中拒绝策略L5J28资讯网——每日最新资讯28at.com

  • 第一种是AbortPolicy,之际抛异常
  • 第二种是CallerRunsPolicy由调用者执行任务
  • 第三是DiscardOldestPolicy丢弃当前的任务
  • 第四是DiscardPolicy丢弃最早排队任务。默认是直接抛异常。

面试官:线程池的执行原理知道吗?

候选人:L5J28资讯网——每日最新资讯28at.com

首先判断线程池里的核心线程是否都在执行任务,如果不是则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队 列里。如果工作队列满了,则判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任 务。如果已经满了,则交给拒绝策略来处理这个任务。L5J28资讯网——每日最新资讯28at.com

面试官:线程池的种类有哪些?

候选人:L5J28资讯网——每日最新资讯28at.com

在jdk中默认提供了4中方式创建线程池L5J28资讯网——每日最新资讯28at.com

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

本文链接:http://www.28at.com/showinfo-26-35298-0.html说一下线程池的核心参数,线程池的执行原理

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 比亚迪面试,全程八股!

下一篇: 线程包括哪些状态,状态之间是如何变化?

标签:
  • 热门焦点
  • 鸿蒙OS 4.0公测机型公布:甚至连nova6都支持

    鸿蒙OS 4.0公测机型公布:甚至连nova6都支持

    华为全新的HarmonyOS 4.0操作系统将于今天下午正式登场,官方在发布会之前也已经正式给出了可升级的机型产品,这意味着这些机型会率先支持升级享用。这次的HarmonyOS 4.0支持
  • 7月安卓手机性价比榜:努比亚+红魔两款新机入榜

    7月安卓手机性价比榜:努比亚+红魔两款新机入榜

    7月登场的新机有努比亚Z50S Pro和红魔8S Pro,除了三星之外目前唯二的两款搭载超频版骁龙8Gen2处理器的产品,而且努比亚和红魔也一贯有着不错的性价比,所以在本次的性价比榜单
  • 掘力计划第 20 期:Flutter 混合开发的混乱之治

    掘力计划第 20 期:Flutter 混合开发的混乱之治

    在掘力计划系列活动第20场,《Flutter 开发实战详解》作者,掘金优秀作者,Github GSY 系列目负责人恋猫的小郭分享了Flutter 混合开发的混乱之治。Flutter 基于自研的 Skia 引擎
  • Automa-通过连接块来自动化你的浏览器

    Automa-通过连接块来自动化你的浏览器

    1、前言通过浏览器插件可实现自动化脚本的录制与编写,具有代表性的工具就是:Selenium IDE、Katalon Recorder,对于简单的业务来说可快速实现自动化的上手工作。Selenium IDEKat
  • 微信语音大揭秘:为什么禁止转发?

    微信语音大揭秘:为什么禁止转发?

    大家好,我是你们的小米。今天,我要和大家聊一个有趣的话题:为什么微信语音不可以转发?这是一个我们经常在日常使用中遇到的问题,也是一个让很多人好奇的问题。让我们一起来揭开这
  • 阿里大调整

    阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的&ldquo;征求意见版&rdquo;:1、取消P序列
  • 华为Mate60标准版细节曝光:经典星环相机模组回归

    华为Mate60标准版细节曝光:经典星环相机模组回归

    这段时间以来,关于华为新旗舰的爆料日渐密集。据此前多方爆料,今年华为将开始恢复一年双旗舰战略,除上半年推出的P60系列外,往年下半年的Mate系列也将
  • 苹果、三星、惠普等暂停向印度出口笔记本和平板电脑

    苹果、三星、惠普等暂停向印度出口笔记本和平板电脑

    集微网消息,据彭博社报道,在8月3日印度突然禁止在没有许可证的情况下向印度进口电脑/平板及显示器等产品后,苹果、三星电子和惠普等大公司暂停向印度
  • 利用职权私自解除被封帐号 Meta开除20多名员工

    利用职权私自解除被封帐号 Meta开除20多名员工

    11月18日消息,据外媒援引知情人士表示,过去一年时间内,Facebook母公司Meta解雇或处罚了20多名员工以及合同工,指控这些人通过内部系统以不当方式重置用户帐号,其
Top