Java线程池

什么是线程池

线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求。然而,增加可用线程数量是可能的。线程池中的每个线程都有被分配一个任务,一旦任务已经完成了,线程回到池子中并等待下一次分配任务。

什么业务场景下需要使用线程池

1、数据量大

比如:一个学生系统,在年终需要做学生整个学习的参与次数等,如果有10000个学生的数据需要计算,那么这个情况下就需要使用线程池来实现。创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)

2:网购商品秒杀
3:云盘文件上传和下载
4:12306网上购票系统等

其他;

  1. 高并发请求处理:当系统面临大量并发请求时,使用线程池可以避免频繁地创建和销毁线程,提高线程的复用性和系统的响应速度。线程池可以控制并发线程的数量,防止系统资源被过度占用,提高系统的并发处理能力。

  2. 异步任务处理:当需要处理大量的异步任务时,使用线程池可以将任务提交到工作队列中,由线程池中的线程来执行。这样可以避免主线程被阻塞,提高系统的并发性能和响应速度。常见的异步任务包括发送邮件、短信通知、数据处理等。

  3. 定时任务调度:当需要定时执行一些任务时,使用线程池可以方便地调度和执行这些任务。线程池可以根据预定的时间间隔或时间表来执行任务,提高任务的准确性和可靠性。常见的定时任务包括定时备份、定时统计、定时任务调度等。

  4. 并行计算任务:当需要进行大规模的并行计算时,使用线程池可以将计算任务分配给多个线程并行执行,提高计算的效率和速度。线程池可以根据计算任务的复杂度和资源需求来调整线程的数量和配置,以充分利用系统资源。

  5. 长时间IO操作:当需要进行一些耗时的IO操作时,使用线程池可以将这些操作交给线程池中的线程来处理,避免阻塞主线程。这样可以提高系统的并发性能和响应速度,同时可以通过设置超时时间来控制IO操作的等待时间。

常用的线程池

常用的线程池有:

(1)SingleThreadExecutor(单线程线程池,自己做一个内存队列 -> 启动后台线程去消费)

(2)FixedThreadExecutor(固定数量线程池):比如说,线程池里面固定就100个线程,超过这个线程数就到队列里面去排队等待

(3)CachedThreadExecutor(自动回收空闲线程,根据需要自动新增线程,传说中的无界线程池):无论有多少任务,根据你的需要,无限制的创建任意多的线程,在最短的时间内来满足你,但是高峰过去之后,如果有大量的线程处于空闲状态,没有活儿可以干,等待60s之后空闲的线程就被销毁了
(4)ScheduledThreadExecutor(线程数量无限制,支持定时调度执行某个线程):提交一个任务,对于这个任务不是立马执行的,是可以设定一个定时调度的逻辑,比如说每隔60s执行一次,这个一般不用,一般来说就用spring schedule的支持

Java的线程池比较重要的几个API:

(1)Executor:代表线程池的接口,有个execute()方法,扔进去一个Runnable类型对象,就可以分配一个线程给你执行

(2)ExecutorService:这是Executor的子接口,相当于是一个线程池的接口,有销毁线程池等方法 -> ExecutorService就代表了一个线程池管理器,会负责管理线程池 -> 线程的创建和销毁 -> 队列排队

(3)Executors:线程池的辅助工具类,辅助入口类,可以通过Executors来快捷的创建你需要的线程池。创建线程池的入口类,包含newSingleThreadExecutor()、newCachedThreadPool()、newScheduleThreadPool()、newFixedThreadPool(),这些方法,就是可以让你创建不同的线程池出来
(4)ThreadPoolExecutor:这是ExecutorService的实现类,这才是正儿八经代表一个线程池的类,一般在Executors里创建线程池的时候,内部都是直接创建一个ThreadPoolExecutor的实例对象返回的,然后同时给设置了各种默认参数。

如果我们要创建一个线程池,两种方式,要么就是Executors.newXX()方法,快捷的创建一个线程池出来,线程池的所有参数设置都采取默认的方式;要么是自己手动构建一个THreadPoolExecutor的一个对象,所有的线程池的参数,都可以自己手动来调整和设置

 

以上表格列出了常见的四种线程池类型:newFixedThreadPoolnewCachedThreadPoolnewScheduledThreadPoolnewSingleThreadExecutor,并对它们在多个维度上进行了对比。

在核心线程数方面,newFixedThreadPoolnewScheduledThreadPool都有固定的核心线程数,而newCachedThreadPool会根据需求动态调整核心线程数。newSingleThreadExecutor只有一个核心线程。

在最大线程数方面,newFixedThreadPoolnewScheduledThreadPool的最大线程数都是固定大小的,而newCachedThreadPool的最大线程数是Integer.MAX_VALUE,意味着可以创建非常多的线程。newSingleThreadExecutor只有一个线程,因此最大线程数也只有一个。

在空闲线程存活时间方面,newFixedThreadPoolnewScheduledThreadPool的空闲线程会立即关闭,而newCachedThreadPool的空闲线程会在60秒后关闭。newSingleThreadExecutor没有空闲线程,因此此项无意义。

在队列类型方面,newFixedThreadPoolnewSingleThreadExecutor使用LinkedBlockingQueue作为队列,newCachedThreadPool使用SynchronousQueuenewScheduledThreadPool使用DelayedWorkQueue

在拒绝策略方面,newFixedThreadPoolnewScheduledThreadPool使用AbortPolicynewCachedThreadPool也使用AbortPolicy,而newSingleThreadExecutor使用CallerRunsPolicy

在定时任务支持方面,只有newScheduledThreadPool支持定时任务调度。

在返回结果支持方面,只有newScheduledThreadPool支持任务返回结果。

示例代码

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {

    public static void main(String[] args) {
        // 创建固定大小的线程池,大小为3
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 提交任务给线程池
        for (int i = 0; i < 5; i++) {
            Runnable task = new Task(i + 1);
            executor.submit(task);
        }

        // 关闭线程池
        executor.shutdown();
    }

    static class Task implements Runnable {
        private int taskId;

        public Task(int taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            System.out.println("Task " + taskId + " 执行中...");
            try {
                // 模拟任务执行时间
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Task " + taskId + " 执行完成");
        }
    }
}

在上面的示例代码中,我们首先使用Executors.newFixedThreadPool()方法创建了一个固定大小的线程池,大小为3个线程。然后,我们使用executor.submit()方法提交了5个任务给线程池,每个任务都是实现了Runnable接口的Task类的实例。Task类代表了要执行的具体任务,其中的run()方法定义了具体的任务逻辑。

每个任务被提交后,线程池会从池中的空闲线程中选择一个来执行任务。任务执行完毕后,线程会返回线程池,并准备接收下一个任务。最后,我们使用executor.shutdown()方法关闭线程池,这将阻止新任务的提交,并等待所有任务执行完成。

总结

Java线程池是Java提供的一种用于管理和复用线程的机制。下面是对Java线程池的总结:

1. 线程池的作用:线程池主要用于管理线程的创建、执行和销毁,以提高线程的复用性和管理性。

2. 线程池的优势:线程池可以减少线程的创建和销毁开销,提高系统的性能和响应速度;可以控制并发线程的数量,防止系统资源被过度占用;可以提供线程的管理和监控功能,方便调试和排查问题。

3. Java中的线程池实现:Java提供了Executors类和ThreadPoolExecutor类来实现线程池。Executors类提供了一些静态方法来创建不同类型的线程池,而ThreadPoolExecutor类则是线程池的底层实现类,提供了更多的配置和自定义选项。

4. 线程池的组成:线程池由线程池管理器、工作队列和线程池线程组成。线程池管理器负责管理线程的创建和销毁,工作队列用于存储待执行的任务,线程池线程负责执行任务。

5. 线程池的配置选项:线程池可以根据需求进行配置,包括线程池的大小、工作队列的大小、线程的优先级、线程的超时时间等。通过合理的配置,可以平衡系统的负载,提高系统的并发性能。

6. 线程池的任务执行方式:线程池可以执行Runnable和Callable类型的任务。Runnable任务没有返回值,而Callable任务可以返回执行结果。线程池会自动分配线程来执行任务,并提供监控和异常处理机制。

总之,Java线程池是一种用于管理和复用线程的机制,可以提高系统的性能、可伸缩性和管理性。通过合理的配置和使用,可以充分利用系统资源,提高并发性能,并提供监控和异常处理机制。在开发中,可以根据实际需求选择合适的线程池类型和配置选项,以提高程序的效率和稳定性。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

谷艳爽faye

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

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

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

打赏作者

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

抵扣说明:

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

余额充值