线程池的参数 以及实现

线程池

线程池的概念

线程池是一种线程使用模式,它可以在程序启动时创建一定数量的线程,并放在池子里备用。当有任务需要执行的时候,线程池就会从线程池中取出一个线程执行任务 ,而不是每次都要创建一个新的线程。

线程池的优点

1、减少线程创建和销毁的开销:创建和销毁线程需要一定的系统资源和时间开销。
2、提高系统性能:可以避免频繁创建和销毁线程,从而提高系统的响应性和执行效率。
3、限制资源使用:通过设置线程池的大小,可以合理系统并发运行的线程数量,避免资源耗尽。
4、便于线程管理:可以统一管理线程的创建、调度和销毁。

创建线程池的方式:

直接上代码看看具体有多少创建线程池的方式


Java 标准库线程池的创建方式总共有几种?分别使用代码创建并演示一下
  工作中使用第 7 种方式创建线程池
 class Thread_2553 {
    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();
        // 7. 自定义线程池,工作中使用这种方法创建线程池,参数含义见课堂讲解内容
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3,
                10,
                10000,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());

    }
}

我们如果要自动实现一个自定义的线程池 我们得先掌握一下标准库中线程池的有关参数 下面我们就要讲一下这些参数的作用

线程池的参数

核心线程数 和 最大线程数

在标准库中线程池也会分为两类线程:
1、核心线程: corePoolSize 相当于公司中的正式员工
2、非核心线程:maximumPoolSize就是核心线程数+非核心线程数 相当于公司中的实习生 或者临时工。

核心线程数参数的设计只要根据任务的数量和处理时间来设定的

动态扩展:

一个线程池,刚被创建出来的时候,里面就只有核心线程这么多线程,假设我现在把线程池的核心线程数 和最大线程数 设置为 5 和 10 。
那么现在线程池就包含有5个线程 。
线程池会提供一个submit方法,往里面添加任务,每个任务都是一个Runnable对象。如果现在添加的任务比较少,5个线程足够处理 ,那就只有5个线程进行工作。
但是如果现在添加的任务比较多,4个线程处理不过来了(相当于现在有很多任务在外面排队等待执行) 这个时候,线程池就会自动创建出新的线程,来支持更多的任务 ,但是创建出来的线程总数,不能超过最大的线程数。等过一段时间之后,任务没有那么多了 ,线程得空了,会释放掉部分线程(回收)。

最大空闲时间(keepAliveTime)

这个参数就是表示非核心线程 ,允许等待的最大空闲时间
非核心线程,要是在线程池不忙的时候,回收掉 而不是立即回收 如果在这段时间中又有任务需要执行 那就继续执行任务 。

相当于你是实习生 实习了一段时间 可能现在公司的业务不是那么多了 公司也不需要那么多人手 ,就会考虑辞退你 会给你一段时间 提前通知你
下个月你就可以办理离职了 但要是在这一个月内 公司又有很多业务需要人去做 公司就暂时不考虑辞退你了。

线程池的任务队列

线程池会提供submit方法,让其他线程把任务交给线程池。
线程池内部需要一个队列这样的数据结构,把要执行的任务保存起来 。
在后面线程池工作就会去队列中取出任务进行执行

拒绝策列

这个参数是所有参数中最正确的,去面试的时候,面试官问你线程池中的参数 其实就是在考你对这个参数的理解。
拒绝策列其实是一个枚举类型 他有很多种拒绝策列

意思就是如果当前任务队列满了 还要继续执行任务怎么办

第一种方法 :ThreadPoolExecutor.AbortPolicy
直接抛出异常 (相当于直接告诉程序猿,任务处理不过来了 直接不干了 代码直接罢工了)

第二种方法:ThreadPoolExecutor.CallerRunsPolicy
给线程池添加任务 ,线程池直接告诉添加任务的程序说 我这边满了 让添加任务的程序自己执行 ,线程池本身 不管了.

第三种方式 : ThreadPoolExecutor.DiscardOldestPolicy
丢弃掉最老的任务,让新的任务去队列中排队执行

第四种方式 : ThreadPoolExecutor.DiscardPolicy
丢弃最新的任务,还是按原来的节奏来执行

上面就是标准库的自定义线程池的所有参数了
下面我们自己实现一个线程池:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;

//   写一个普通的线程池
class MyTreadPool {
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);
    private int maxPoolSize = 0;
    private List<Thread> threadList = new ArrayList<>();   //用链表来存储一下线程

    //初始化线程池
    public MyTreadPool(int corePoolSize,int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;

        //创建若干个线程   核心线程
        for (int i = 0; i < corePoolSize; i++) {
            Thread t = new Thread(() -> {
                try {
                    while (true) {
                        Runnable runnable = queue.take();
                        runnable.run();
                    }
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t.start();
            threadList.add(t);
        }
    }

    //把任务添加到线程池中   submit方法
    void submit (Runnable runnable) throws InterruptedException {
        //如果现在任务比较长   说明已有的线程不足以处理这些任务  得新建线程
        queue.put(runnable);

        if (queue.size() >= 500 && threadList.size() < maxPoolSize) {
            //创建新的线程
            Thread t = new Thread(() -> {
                try {
                    while (true) {
                        Runnable task = queue.take();
                        task.run();
                    }
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t.start();
        }
    }
}

public class Text {
    public static void main(String[] args) throws InterruptedException {
        //实例化一个线程池对象
        MyTreadPool myTreadPool = new MyTreadPool(10,20);
        for (int i = 0; i < 10000; i++) {
            int id = i;
            myTreadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello" + id +"," +Thread.currentThread().getName());
                }
            });
        }
    }
}

好了 本篇内容就到这 感谢大家的浏览 和点赞

  • 26
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值