java如何自定义线程线程池

1. ThreadPoolExecutor 构造方法

ThreadPoolExecutor 是 Java 并发库中的核心类,用于实现线程池。它的构造方法如下:

public ThreadPoolExecutor(
    int corePoolSize,                          // 核心线程数
    int maximumPoolSize,                       // 最大线程数
    long keepAliveTime,                        // 非核心线程的空闲保持时间
    TimeUnit unit,                             // 空闲时间的时间单位
    BlockingQueue<Runnable> workQueue,         // 任务队列
    ThreadFactory threadFactory,               // 线程工厂
    RejectedExecutionHandler handler           // 拒绝策略
)
参数解释:
  1. corePoolSize:核心线程数,即使线程是空闲的,也不会被销毁的线程数。
  2. maximumPoolSize:最大线程数,当任务较多时,线程池允许创建的最大线程数量。
  3. keepAliveTime:非核心线程的空闲时间,超过该时间的空闲线程将被销毁。
  4. unitkeepAliveTime 参数的时间单位。
  5. workQueue:用于存放等待执行任务的队列,通常使用 BlockingQueue 的实现类,如 LinkedBlockingQueueSynchronousQueueArrayBlockingQueue 等。
  6. threadFactory:线程工厂,用于创建新线程,通常可以用来给线程设置名字、优先级等。
  7. handler:拒绝策略,当任务过多且队列已满时,线程池如何处理新任务。可以选择 Java 提供的四种拒绝策略,也可以自定义。

2. 自定义线程池的步骤

自定义线程池的步骤包括以下几个方面:

  1. 选择合适的任务队列(BlockingQueue:根据应用场景选择适当的任务队列类型。
  2. 自定义线程工厂(ThreadFactory:通过自定义线程工厂,可以为线程设置特定的名称、优先级等。
  3. 选择或自定义拒绝策略(RejectedExecutionHandler:根据任务负载情况选择合适的拒绝策略,或者自定义拒绝策略。
  4. 配置核心线程数和最大线程数:根据实际需求合理配置核心线程数和最大线程数。
  5. 配置空闲线程存活时间:根据任务的执行时间和频率,设置适当的空闲线程存活时间。

3. 自定义线程池的示例

下面是一个自定义线程池的示例,其中包含了自定义线程工厂、自定义拒绝策略,并使用了 LinkedBlockingQueue 作为任务队列。

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

// 自定义线程工厂类
class CustomThreadFactory implements ThreadFactory {
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    public CustomThreadFactory(String namePrefix) {
        this.namePrefix = namePrefix;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r, namePrefix + "-thread-" + threadNumber.getAndIncrement());
        System.out.println("创建新线程:" + t.getName());
        return t;
    }
}

// 自定义拒绝策略类
class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("任务被拒绝:" + r.toString());
    }
}

public class CustomThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2,                              // 核心线程数
            4,                              // 最大线程数
            60L,                            // 非核心线程的空闲时间
            TimeUnit.SECONDS,               // 空闲时间的单位
            new LinkedBlockingQueue<>(2),   // 任务队列,容量为2
            new CustomThreadFactory("CustomPool"),  // 自定义线程工厂
            new CustomRejectedExecutionHandler()    // 自定义拒绝策略
        );

        // 提交多个任务给线程池
        for (int i = 1; i <= 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " 执行任务 " + taskId);
                try {
                    Thread.sleep(2000); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}
示例分析
  1. 自定义线程工厂 CustomThreadFactory

    • 通过实现 ThreadFactory 接口来自定义线程工厂,可以在创建新线程时为线程设置名称(方便调试和监控),也可以设置线程的优先级等属性。
    • 本例中,线程名称被设置为 "CustomPool-thread-X" 的形式。
  2. 自定义拒绝策略 CustomRejectedExecutionHandler

    • 通过实现 RejectedExecutionHandler 接口来自定义拒绝策略,当任务被拒绝时执行自定义操作(如记录日志、通知开发人员等)。
    • 本例中,当任务被拒绝时,输出“任务被拒绝”的信息。
  3. 自定义线程池 ThreadPoolExecutor

    • 设置核心线程数为 2,最大线程数为 4,使用 LinkedBlockingQueue 作为任务队列,队列容量为 2。
    • 线程池可以同时运行 2 个核心线程,如果任务数量超过核心线程数,会先将任务放入队列。当队列已满时,如果线程数量小于最大线程数,则会创建新的线程来执行任务。如果线程数量已达到最大线程数且任务队列也已满,则执行自定义的拒绝策略。
  4. 提交任务并关闭线程池

    • 提交了 10 个任务给线程池,其中前 4 个任务可以正常被执行(2 个核心线程 + 2 个排队任务)。从第 5 个任务开始,由于线程池已达到最大容量,后续任务将会被拒绝,并触发自定义的拒绝策略。

4. ThreadPoolExecutor 的拒绝策略

ThreadPoolExecutor 提供了四种内置的拒绝策略,当线程池无法接受新任务时,这些策略决定了如何处理新任务:

  1. AbortPolicy(默认):直接抛出 RejectedExecutionException 异常。
  2. CallerRunsPolicy:由调用线程(提交任务的线程)直接执行被拒绝的任务。
  3. DiscardPolicy:直接丢弃任务,不抛出任何异常。
  4. DiscardOldestPolicy:丢弃任务队列中最旧的任务,然后尝试提交新任务。

开发者可以根据实际需求选择适合的拒绝策略,或者通过实现 RejectedExecutionHandler 接口来自定义拒绝策略。

5. 自定义线程池的使用建议

  1. 根据任务特性选择适当的任务队列:例如,使用 LinkedBlockingQueue 可以缓解任务堆积压力,而 SynchronousQueue 可以快速创建新线程处理任务,但可能会导致线程数量过多。

  2. 合理配置线程数和队列大小:根据应用场景和服务器硬件资源,合理配置核心线程数、最大线程数和队列大小,避免过多的上下文切换或资源耗尽。

  3. 优先选择内置的拒绝策略:如果内置的拒绝策略不能满足需求,可以自定义拒绝策略来更好地控制任务的拒绝行为。

  4. 监控和调优:在生产环境中,建议监控线程池的使用情况(如线程数量、队列大小、拒绝任务数等),根据实际运行情况不断调整线程池的参数配置。

6. 总结

自定义线程池是 Java 并发编程中非常重要的一项技能。通过自定义 ThreadPoolExecutor,可以更灵活地控制线程池的行为和性能。

在 Java 中,自定义线程池可以通过使用 ThreadPoolExecutor 类来实现。ThreadPoolExecutor 是 Java 提供的一个灵活且功能强大的线程池实现类,允自定义线程池的各种参数(如核心线程数、最大线程数、任务队列、线程工厂、拒绝策略等)来满足特定的需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Flying_Fish_Xuan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值