经典设计模式之 -- 线程池

目录

一、线程池的概念

二、Java 标准库中的线程池类

2.1 ThreadPoolExecutor 类

2.1.1 corePoolSize 和 maximumPoolSize

2.1.2 keepAliveTime 和 unit

2.1.3 workQueue

2.1.4 threadFactory

2.1.5 handler

2.1.6 创建一个参数自定义的线程池

2.2 Executors 类

2.3 实现自己的线程池


一、线程池的概念

1)什么是线程池?

准备预期需要使用的对象,将这些对象放入一个可以随时取用的容器中,这个容器就被称为“池”。

使用过的对象也不立刻销毁,而是放回“池”中,以备下次使用。

将线程作为上述对象,放在一个容器中,这就称为“线程池”。

2)为什么使用线程池?
在实际使用中,“线程池”并没有频繁的创建和销毁线程,而是从“池”中存取线程,这样可以减少每次启动和销毁线程的损耗,提高运行效率,减小系统开销。
3)为什么使用线程池可以提高效率?

通常创建线程,是通过向系统申请创建,需要通过系统内核完成,是具有内核态的代码。

而从线程池中存取线程,是属于用户态的代码,相比于内核态代码更可控、稳定,操作更快。


二、Java 标准库中的线程池类

2.1 ThreadPoolExecutor 类

这个类的构造方法参数众多,包含以下参数:

int corePoolSize

核心线程数

int maximumPoolSize

最大线程数

long keepAliveTime

空闲线程存活时间

TimeUnit unit

时间单位

BlockingQueue<Runnable> workQueue

任务队列

ThreadFactory threadFactory

线程工厂

RejectedExecutionHandler handler

拒绝策略

2.1.1 corePoolSize 和 maximumPoolSize

int corePoolSize 核心线程数

线程池中保持持有的最小线程数量。

int maximumPoolSize 最大线程数

线程池中可以持有的最大线程数量。
标准库提供的线程池,持有的线程数量是可以变动的,可以根据需要执行的任务数量,自适应线程的数量。

2.1.2 keepAliveTime 和 unit

long keepAliveTime 空闲线程存活时间

当线程池中的线程处于空闲状态时,会等待 keepAliveTime 时间后自动关闭。

如果keepAliveTime为0,线程在执行完任务后则不会关闭。

TimeUnit unit 时间单位
keepAliveTime 空闲线程存活时间的时间单位。

2.1.3 workQueue

BlockingQueue<Runnable> workQueue 任务队列

用于存储等待执行的任务。当线程池中的线程数量达到最大值时,新任务将被添加到队列中等待执行。

执行的任务应该是 Runnable 接口的实现类,

2.1.4 threadFactory

前置知识点:工厂模式

什么是工厂模式?

工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种在不指定具体类的情况下创建对象的接口。

工厂模式的核心思想是,将对象的创建过程抽象出来,使得使用者的创建与类的实例化过程解耦。

在工厂模式中,会实现一个工厂类,它提供一个创建对象的接口,而使用者只需要调用这个接口即可,工厂类会根据客户端的请求,返回不同类型的对象。

threadFactory 具体指什么:

ThreadFactory threadFactory 线程工厂
通过工厂类创建线程对象(简单理解就是通过这个类产出线程)。ThreadFactory 是一个接口,接口中只中有一个方法 newThread 方法,通过覆写该方法获得一个线程,同时可以给这个新线程设置一些属性。

2.1.5 handler

RejectedExecutionHandler handler 拒绝策略
线程池异常处理器,也称拒绝策略。这里的 handler 表示一个实现了 RejectedExecutionHandler 接口的实现类,传入的 handler 参数决定了出现异常时,线程池如何处理异常。
有哪几种拒绝策略,分别表示什么?
ThreadPoolExecutor.AbortPolicy当线程池已满,且阻塞队列已满,新任务无法执行,则立即抛出 RejectedExecutionException 异常,是默认策略。
ThreadPoolExecutor.CallerRunspolicy当线程池已满,且阻塞队列已满,新任务无法执行,则由调用线程自己执行新任务。
ThreadPoolExecutor.DiscardOldestPolicy当线程池已满,且阻塞队列已满,新任务无法执行,则丢弃最早添加的任务,然后添加新任务。
ThreadPoolExecutor.DiscardPolicy当线程池已满,且阻塞队列已满,新任务无法执行,则丢弃新任务,不执行。

2.1.6 创建一个参数自定义的线程池

创建并运行以下线程池和任务:

分析上述代码运行结果:

2.2 Executors 类

1)简单介绍 Executors 类

ThreadPoolExecutor 类参数较多,使用较复杂。因此,为方便使用,标准库中又提供了 Executors 工厂类。

Executors 类是对 ThreadPoolExecutor 类进行了一层封装,是一个工厂类,通过这个类创建出不同属性的线程池对象。
Executors 类返回的是一个 ExecutorService 类型的线程池实例。通过 ExecutorServic.submit 可以向线程池中添加任务。
2)简单介绍常用的 Executors 类创建线程池的方法

newFixedThreadPool

创建固定线程数的线程池

newCachedThreadPool

创建线程数目动态增长的线程池

newSingleThreadExecutor

创建只包含单个线程的线程池

newScheduledThreadPool

创建可以定时执行任务的线程池
3)开发过程中应该使用 ThreadPoolExecutor 类还是使用 Executors 类?

ThreadPoolExecutor 类参数较多、可以自定义,这意味着使用这个类创建的线程池更灵活。

而 Executors 类相比 ThreadPoolExecutor 类多了一层封装,部分参数已经设定好,这使得 Executors 类在使用上更便利。

这两种选择,前者更偏向于高度定制化的线程池,而后者偏向于通用性。两者并无高下之分,各有偏向,使用者根据实际应用场景使用即可。

2.3 实现自己的线程池

线程池的使用有以下关键点:

<1>

线程池,肯定要有线程。在这里实现一个线程数量固定的线程池,就需要在这个类的构造方法中,根据输入的参数 n ,新建 n 个线程。
<2>维护一个阻塞队列,队列持有需要执行的任务。
<3>提供一个 submit 方法,用于将任务添加到任务队列中。
<4>线程池中的线程,也有自己的任务,就是不断地扫描任务队列,如果队列中有任务,则取出任务后执行。
<5>注意新建的线程需要有合适的启动时机。在以下实现中,我们让线程一创建就启动。

代码演示线程池的实现:

class MyThreadPool{
    //创建一个用于存放任务的队列;
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(5);

    //构造方法,用于构造线程池。方法中需要将线程new出来;
    public MyThreadPool(int n){
        //设置线程需要执行的任务;
        Runnable runnable = new  Runnable() {
            @Override
            public void run() {
                while (true){
                    try {
                        //从任务队列中取出任务,并执行;
                        queue.take().run();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        //循环创建线程,并启动,将线程放入队列中;
        for (int i = 0; i < n; i++){
            Thread t = new Thread(runnable);
            t.start();
        }
    }

    //添加任务方法。往任务队列中添加任务;
    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
}
public class ThreadPool_Demo35 {
    public static void main(String[] args) throws InterruptedException {
        //新建线程池;
        MyThreadPool threadPool = new MyThreadPool(2);

        //给线程池添加任务;
        for (int i= 0; i < 10; i++){
            int n = i;
            threadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " 执行任务:" + n);
                }
            });
        }
    }
}


//运行结果:
Thread-0 执行任务:0
Thread-1 执行任务:1
Thread-0 执行任务:2
Thread-1 执行任务:3
Thread-0 执行任务:4
Thread-0 执行任务:6
Thread-0 执行任务:7
Thread-0 执行任务:8
Thread-0 执行任务:9
Thread-1 执行任务:5
...

十个任务全部成功打印。
应该注意到,线程没有执行结束,还在等待新的任务加入,这是线程池的合理功能。

阅读指针 -> 《 Synchronized 锁进阶 -- 锁策略》

锁进阶 -- 锁策略(乐观锁和悲观锁、重量级锁和轻量级锁、自旋锁和挂起等待锁、可重入锁和不可重入锁、公平锁和非公平锁、读写锁)-CSDN博客介绍了以下锁策略:乐观锁和悲观锁、重量级锁和轻量级锁、自旋锁和挂起等待锁、可重入锁和不可重入锁、公平锁和非公平锁、读写锁;https://blog.csdn.net/zzy734437202/article/details/134916407

  • 37
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java设计模式是一组经过实践验证的面向对象设计原则和模式,可以帮助开发人员解决常见的软件设计问题。下面是常见的23种设计模式: 1. 创建型模式(Creational Patterns): - 工厂方法模式(Factory Method Pattern) - 抽象工厂模式(Abstract Factory Pattern) - 单例模式(Singleton Pattern) - 原型模式(Prototype Pattern) - 建造者模式(Builder Pattern) 2. 结构型模式(Structural Patterns): - 适配器模式(Adapter Pattern) - 桥接模式(Bridge Pattern) - 组合模式(Composite Pattern) - 装饰器模式(Decorator Pattern) - 外观模式(Facade Pattern) - 享元模式(Flyweight Pattern) - 代理模式(Proxy Pattern) 3. 行为型模式(Behavioral Patterns): - 责任链模式(Chain of Responsibility Pattern) - 命令模式(Command Pattern) - 解释器模式(Interpreter Pattern) - 迭代器模式(Iterator Pattern) - 中介者模式(Mediator Pattern) - 备忘录模式(Memento Pattern) - 观察者模式(Observer Pattern) - 状态模式(State Pattern) - 策略模式(Strategy Pattern) - 模板方法模式(Template Method Pattern) - 访问者模式(Visitor Pattern) 4. 并发型模式(Concurrency Patterns): - 保护性暂停模式(Guarded Suspension Pattern) - 生产者-消费者模式(Producer-Consumer Pattern) - 读写锁模式(Read-Write Lock Pattern) - 信号量模式(Semaphore Pattern) - 线程池模式(Thread Pool Pattern) 这些设计模式可以根据问题的特点和需求来选择使用,它们提供了一些可复用的解决方案,有助于开发高质量、可维护且易于扩展的软件系统。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值