线程池的创建和使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

线程池复习梳理

线程池概念

线程池其实就是一个容纳多个线程的容器,其中线程可以反复利用,省去了频繁创建线程对象的操作,无序
在这里插入图片描述
合理利用线程池能够带来三个好处:

  1. 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

线程池的创建

创建线程的两种方式

  • 通过ExecutorService的实现类ThreadPoolExecutor,通过创建ThreadPoolExecutor对象来实现线程池的创建。
    通过阅读源码:
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

可以看到这个类的构造器,包含了一些参数。
稍后解释这些参数的含义
corePoolSize:指定线程池的核心线程数量。
maximumPoolSize:指定线程池最大线程数量。
keepAliveTime:指定临时线程的存活时间。(临时线程闲置了**时间后就会被干掉)
unit:指定临时线程的存活时间单位。
workQueue:指定线程池的任务队列。
threadFactory:指定线程池的线程工厂。(指定哪个线程工厂来创建)
handler:指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新来的任务该如何处理)。
在这里插入图片描述

  • 通过Executors(线程池工具类)调用一些方法,来创建线程池

例子

 public static void main(String[] args) {
       /* public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        RejectedExecutionHandler handler) {*/
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }

线程池的注意事项:

  1. 临时线程什么时候创建?
    答:新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以允许创建临时线程,此时才会去创建临时线程。
  2. 什么时候开始拒绝新任务?
    核心线程、临时线程都子啊忙,任务队列也满了,此时才会去拒绝。

线程池处理Runnable任务

在这里插入图片描述
下面用一个例子来说明:
先创建一个Runnable任务

public class MineRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"==> 输出666");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

在主线程中创建线程池,并且分配执行

public class ThreadPoolsDemo01 {
    public static void main(String[] args) {
       /* public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        RejectedExecutionHandler handler) {*/
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        MineRunnable target = new MineRunnable();
        pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
        pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
        pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
        pool.execute(target); //复用核心线程,执行任务
        pool.execute(target); //复用核心线程,执行任务
    }
}

我们增加几个线程去填满等待队列试试看:

pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
        pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
        pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
        pool.execute(target); //复用核心线程,执行任务
        pool.execute(target); //复用核心线程,执行任务
        pool.execute(target); //复用核心线程,执行任务
        pool.execute(target); //复用核心线程,执行任务
        pool.execute(target); //复用核心线程,执行任务

在这里插入图片描述
可以看到多了几个临时线程。

那我们再次添加呢?
在这里插入图片描述
可以看到这里抛出了异常,这就是任务拒绝策略,当前使用的拒绝策略是直接丢弃任务,并且抛出异常。

任务拒绝策略

在这里插入图片描述
以上代码都是使用AbortPolicy的结果
当我们改成CallerRunsPolicy呢?
在这里插入图片描述
可以看到,主线程也开始输出了

线程池处理Callable任务

  • Callable和Runnable任务有什么不同?
    Callable任务是可以返回任务结果的
    在这里插入图片描述
    一样做一个例子演示:
    创建Callable的任务线程类
public class MineCallable implements Callable {
    private int n;

    public MineCallable(int n) {
        this.n = n;
    }

    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int  i = 0; i<n;i++){
            sum += i;
        }
        return  Thread.currentThread().getName()+ "==>" + n + "数求和的结果是:" + sum;
    }
}


public class MineCallable implements Callable {
    private int n;

    public MineCallable(int n) {
        this.n = n;
    }

    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int  i = 0; i<n;i++){
            sum += i;
        }
        return  Thread.currentThread().getName()+ "==>" + n + "数求和的结果是:" + sum;
    }
}

在这里插入图片描述

Executor工具类实现线程池(少使用)

在这里插入图片描述

 //通过Executors创建一个线程对象
        ExecutorService pool1 = Executors.newFixedThreadPool(3);

Executors使用可能存在的陷阱

  • 大型并发系统环境中使用Executors如果不注意会出现系统风险。
    在这里插入图片描述

OOM:内存溢出异常
Executors创建的线程,会因为任务过多/创建线程过多,导致内存溢出。
前两者会导致任务过多堆积
最后的Cached,多少任务进入多少线程就会被创建

注意:
这些方法的底层,都是通过线程池实现类ThreadExecutor创建的线程池对象。

核心线程数量到底配置多少呢?

  • 计算密集型任务:核心线程数量 = CPU核数 + 1;
  • IO密集型任务:核心线程数 = CPU核数*2 + 1;
    计算密集型:大多由CPU去计算的任务,比如100的累加(计算)
    IO密集型:提取文件数据,通信。
    CPU核数: Ctrl + Alt + Delete键
    打开任务管理器 --> 性能
    在这里插入图片描述
  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用线程池创建线程有以下好处:首先,线程池的设计是为了解决频繁创建和销毁线程的效率问题。当系统中需要并发执行大量任务,并且每个任务的执行时间很短,频繁创建和销毁线程会消耗大量的系统资源和时间。通过使用线程池,可以复用线程,避免频繁创建和销毁线程,从而提高系统的效率。\[2\] 其次,线程池可以降低资源消耗。通过复用线程,可以减少创建线程的开销,提高系统资源的利用率。假设有多个子任务需要执行,如果为每个子任务都创建一个执行线程,那么创建线程的过程会消耗一定的系统资源,最终会拖慢整个系统的处理速度。而通过线程池,可以复用线程,减少创建线程的开销,提高系统资源的利用率。\[3\] 此外,线程池还可以提供线程的管理和控制。线程池可以限制线程的数量,避免线程数量过多导致系统资源耗尽。同时,线程池还可以提供线程的监控和统计功能,方便对线程的执行情况进行管理和调优。 综上所述,使用线程池创建线程可以提高系统的效率,降低资源消耗,并提供线程的管理和控制功能。 #### 引用[.reference_title] - *1* [线程池的好处,详解,单例(绝对好记)](https://blog.csdn.net/fengye454545/article/details/79536986)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Java线程池中的核心线程是如何被重复利用的?](https://blog.csdn.net/MingHuang2017/article/details/79571529)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值