Java线程池的使用

本文深入探讨了Java线程池的概念,强调了其在资源管理和性能优化方面的重要性。介绍了线程池的创建方式,包括固定大小、可缓存、单线程、延迟任务等类型,并通过代码示例展示了每种类型的使用。此外,文章分析了线程池的拒绝策略,钩子方法以及相关监控统计方法,最后总结了线程池的创建和使用注意事项,尤其是对可能导致OOM的情况进行了警告。
摘要由CSDN通过智能技术生成

概述

线程池(ThreadPool)是一种多线程处理形式,也就是线程的一种使用模式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。

每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。

如果某个线程在空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。

如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。

超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。

线程池提供了一种限制、管理资源的策略。 每个线程池还维护一些基本统计信息,例如已完成任务的数量。

池化思想在计算机的应用也比较广泛,比如以下这些:

  • 内存池(Memory Pooling):预先申请内存,提升申请内存速度,减少内存碎片。
  • 连接池(Connection Pooling):预先申请数据库连接,提升申请连接的速度,降低系统的开销。
  • 实例池(Object Pooling):循环使用对象,减少资源在初始化和释放时的昂贵损耗。

线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。

线程池的优势主要体现在以下 4 点:

  1. 降低资源消耗:通过池化技术重复利用已创建的线程,降低线程创建和销毁造成的损耗。
  2. 提高响应速度:任务到达时,无需等待线程创建即可立即执行。
  3. 提高线程的可管理性:线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会因为线程的不合理分布导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、调优和监控。

线程池的使用

Java线程池提供了两种创建形式:

1、通过Executors类创建;

2、通过ThreadPoolExecutor类创建。

除了newWorkStealingPool创建方式,其他方式本质上都是通过ThreadPoolExecutor类进行创建。

Executors类创建

Executors类提供了6种静态方法创建线程池,如下所示:

  1. Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
  2. Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程;
  3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
  4. Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
  5. Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;
  6. Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】。
具体使用方式

一、Executors.newFixedThreadPool

创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待。

1、代码示例

ExecutorService fixedService = Executors.newFixedThreadPool(2);
Runnable task = new Runnable() {
   
    @Override
    public void run() {
   
        Log.e(TAG, "任务线程名: "+Thread.currentThread().getName());
    }
};
// 执行5次
fixedService.execute(task);
fixedService.execute(task);
fixedService.execute(task);
fixedService.execute(task);
fixedService.execute(task);

执行结果:

MainActivity: 任务线程名: pool-2-thread-2
MainActivity: 任务线程名: pool-2-thread-2
MainActivity: 任务线程名: pool-2-thread-1
MainActivity: 任务线程名: pool-2-thread-2
MainActivity: 任务线程名: pool-2-thread-1

从执行结果可以看出线程只能执行固定两个线程,当执行中的两个线程还没有执行完毕,超出的线程会在队列中等待。

2、源码分析

查看newFixedThreadPool的源码,如下:

public static ExecutorService newFixedThreadPool(int nThreads) {
   
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

可以看到使用的是通过创建ThreadPoolExecutor类来实现的,ThreadPoolExecutor会在下面详情说明,从源码中可以得知:

  • 核心线程数和最大线程数同时设置为nThreads;
  • 最大线程数可以存活的时间为0;
  • 时间单位为毫秒;
  • 阻塞队列使用的是:链表有界阻塞队列。

二、Executors.newCachedThreadPool

创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程。

1、代码示例

ExecutorService cachedService = Executors.newCachedThreadPool();
Runnable task = new Runnable() {
   
    @Override
    public void run() {
   
        Log.e(TAG, "任务线程名: " + Thread.currentThread().getName());
    }
};
for (int i = 0; i < 10; i++) {
   
    cachedService.execute(task);
}

执行结果:

MainActivity: 任务线程名: pool-1-thread-1
MainActivity: 任务线程名: pool-1
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Java线程池提供了一种线程复用的机制,以及一些控制和管理线程的方法。它可以帮助我们更好地管理线程,提高应用程序的性能。 以下是使用Java线程池的步骤: 1. 创建线程池对象 可以使用Executors类提供的静态方法来创建线程池对象,如下所示: ``` ExecutorService executor = Executors.newFixedThreadPool(10); ``` 这里使用了newFixedThreadPool方法来创建一个固定大小的线程池,最多可以同时执行10个任务。 2. 提交任务 将任务提交给线程池,如下所示: ``` executor.execute(new Runnable() { public void run() { // 执行任务的代码 } }); ``` 这里使用了execute方法将任务提交给线程池。你可以将任务封装在Runnable接口的实现类中,并将其作为参数传递给execute方法。 3. 关闭线程池 当你的应用程序不再需要线程池时,应该关闭它,以释放资源。可以使用shutdown方法来关闭线程池,如下所示: ``` executor.shutdown(); ``` 这里使用了shutdown方法来关闭线程池。调用shutdown方法后,线程池将不再接受新的任务,但会等待所有已提交的任务执行完毕,然后关闭线程池。 除了newFixedThreadPool方法外,Java线程池还提供了其他的线程池类型,如newCachedThreadPool、newSingleThreadExecutor等,可以根据需要选择合适的线程池类型。同时,线程池还提供了一些控制和管理线程的方法,如setCorePoolSize、setMaximumPoolSize、setKeepAliveTime等,可以根据需要进行配置。 ### 回答2: Java线程池是用来管理和利用线程的一种机制。它可以有效地将有限的资源(线程)进行分配和复用,提高程序的性能和资源利用率。 使用线程池可以带来一系列好处。首先,线程池能够控制并发的线程数量,避免过多的线程导致系统资源的浪费。其次,线程池可以重复利用已创建的线程,避免频繁地创建和销毁线程的开销。再次,线程池可以对线程进行管理,比如设置线程的优先级、超时时间等,提高了线程的效率。最后,线程池还可以提供线程的监控和统计信息,方便进行系统性能的调优。 在Java中,线程池一般会使用Executor框架来实现。常见的线程池实现类有ThreadPoolExecutor和ScheduledThreadPoolExecutor。 通过ThreadPoolExecutor类,我们可以创建一个线程池,并指定线程的初始大小、最大大小、线程空闲时的存活时间等参数。我们可以将任务提交给线程池执行,线程池会自动选择一个可用的线程来执行任务。当任务执行完毕后,线程会返回线程池继续等待下一个任务的分配。 使用线程池时,应该根据具体情况来配置线程池的参数。如果任务量较大,可以适当增加线程池的大小,以充分利用系统资源。如果任务量较小,可以适当减少线程池的大小,避免资源的浪费。同时,应该注意合理设置线程的优先级和超时时间,以保证任务的顺利执行。 总之,Java线程池使用能够提高程序的性能和资源利用率,减少线程的创建和销毁开销,对于多线程编程是非常有益的工具。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ruiurrui

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

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

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

打赏作者

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

抵扣说明:

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

余额充值