线程池(面试常考)

目录

🍊一. 认识线程池

🍉二. 原生线程池(ThreadPoolExecutor)

🍏三. ExecutorService 和 Executors创建线程池

🫐四. 线程池的工作流程

🍋五. 线程池的模拟实现


🍊一. 认识线程池

关于“池”的概念,我们接触过字符串常量池数据库连接池,它们都被用作共享和缓存资源,通俗的将就是使用的时候直接从池子里拿,线程池也一样,在初始化的时候,就创建一定数量元素,后面需要使用线程就直接从线程池中取

我们之前使用多线程的时候都会创建线程和销毁线程,但是创建和销毁都会耗费大量资源,所以线程池的作用就是减小创建和销毁时的损耗

🍬举例形象说明线程池:

我们假设线程池为一个快递公司,里面有正式员工,但是在双11,双12因为快递量大所以有临时工,但是高峰期过后需要解雇临时工,快递都放在仓库,当仓库满了之后就不在接收快递,快递员送快递是从仓库拿快递然后送

🍉二. 原生线程池(ThreadPoolExecutor)

ThreadPoolExecutor提供了更多的参数,可以进一步细化线程池的行为

🍬ThreadPoolExecutor的构造方法:

🍬构造方法参数解析:对应上述例子来结合理解

🍃corePoolSize,核心线程数:正式员工
🍃maximumPoolSize,最大线程数:正式员工和临时员工总数
🍃keepAliveTime,空闲时间:临时工空闲(keepAliveTime,TimeUnit结合来决定何时解雇临时工)
🍃TimeUnit,空闲时间单位:空闲时间(keepAliveTime,TimeUnit结合来决定何时解雇临时工)
🍃workQueue,阻塞队列:快递仓库
🍃threadFactory:使用工厂对象提供的方法来创建线程(了解)
🍃RejectedExecutionHandler,拒绝策略:仓库满了不再接收快递

🍬拒绝策略:

🍂AbortPolicy():抛出异常的方式拒绝(默认的拒绝策略)
🍂CallerRunsPolicy():调用的线程来处理
🍂DiscardOldestPolicy():丢弃时间最久的任务(先进先出)
🍂DiscardPolicy():丢弃新来的任务

👁‍🗨️实现代码:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

//使用原生api来创建(ThreadPoolExecutor)
public class ThreadPool {
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                3, //线程核心数
                10, //最大线程数
                60,  //空闲时间
                TimeUnit.SECONDS, //空闲时间单位
                new ArrayBlockingQueue<>(100), //阻塞队列
                new ThreadPoolExecutor.AbortPolicy()  //默认拒绝策略,抛出异常
//                new ThreadPoolExecutor.CallerRunsPolicy() 让调用线程自己处理
//                new ThreadPoolExecutor.DiscardOldestPolicy() 丢弃时间最久任务
//                new ThreadPoolExecutor.DiscardPolicy() 丢弃新来的任务
        );
        //提交任务使用:submit/execute
        for(int i = 0;i < 10;i++){
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

🍏三. ExecutorService 和 Executors创建线程池

这种创建方式对应就是ThreadPoolExecutor构造参数中的threadFactory参数,使用工厂对象提供的创建方式

ExecutorService 表示一个线程池实例
Executors 是一个工厂类, 能够创建出几种不同风格的线程池

提交任务到线程池中的阻塞队列中:
🍁execute(Runnable task)
🍁submit(Runnable task)
🍁submit(Callable task)

🍬Executors创建线程池的几种方式:i

☘️newFixedThreadPool:创建固定线程数的线程池
☘️newCachedThreadPool:创建线程数目动态增长的线程池
☘️newSingleThreadExecutor:创建只包含单个线程的线程池
☘️newScheduledThreadPool:创建有计划任务的线程池(带有定时器功能)

👁‍🗨️示例代码:

        //创建有缓存的线程池
        ExecutorService pool1 = Executors.newCachedThreadPool();
        //创建有固定大小的线程池
        ExecutorService pool2 = Executors.newFixedThreadPool(4);
        //创建有计划任务的线程池
        ExecutorService pool3 = Executors.newScheduledThreadPool(4);
        //创建只有单个线程的线程池
        ExecutorService pool4 = Executors.newSingleThreadExecutor();

👁‍🗨️注意:这种创建的方式在以后的工作中不建议用

🍂在工作中要阻塞队列设置大小,如果不设置大小,在某个时间会导致内存不够,出现OOM(内存溢出)
🍂拒绝策略要自己扩展实现(比如任务记录在日志或者数据库里) 

🫐四. 线程池的工作流程

结合上述快递公司例子说明:


 

🍋五. 线程池的模拟实现

前提说明:

🍁这里阻塞队列的实现采用链表的方式阻塞
🍁我们要求线程池创建的时候,就创建线程不停的从队列中取任务来执行
🍁这里创建5个员工

👁‍🗨️代码实现:

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class MyThreadPool {
    private BlockingDeque<Runnable> queue = new LinkedBlockingDeque<>();

    //员工的数量
    public MyThreadPool(int num){
        for(int i = 0;i < num;i++){
            //线程池创建的时候,就创建线程不停的从队列中取任务来执行
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){ //不停的取任务
                        try {
                            Runnable task = queue.take(); //获取任务
                            task.run(); //执行任务
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }

    //放任务
    public void execute(Runnable task){
        try {
            queue.put(task);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThreadPool pool = new MyThreadPool(5);
        while(true){
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
            Thread.sleep(1000);
        }
    }
}

部分打印结果:

  • 30
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 19
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X_H学Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值