java学习之线程池

本文详细介绍了Java线程池的优势,如降低创建/销毁开销、提高性能和线程管理,以及ThreadPoolExecutor构造函数的各个参数含义。同时讨论了线程池的使用场景和不同类型的拒绝策略。最后,提到了通过Executors类创建常见线程池的方法及其应用场景。
摘要由CSDN通过智能技术生成

java线程池优点:

  1. 降低线程创建和销毁的开销,提高系统性能。

  2. 提高线程的利用率和系统的吞吐量。

  3. 统一线程的管理和监控,避免线程泄漏和线程安全问题。

  4. 支持任务队列和拒绝策略等机制,提供灵活的任务调度和任务处理能力。

并不是所有的业务场景都需要线程池,因为线程池中会涉及到调度相关的内容,如果业务量非常少,并且应用了线程池,可能会导致性能降低。

一、ThreadPoolExecutor线程池实例构造函数如下:

public ThreadPoolExecutor(int corePoolSize, // 核心线程数
                          int maximumPoolSize, // 最大线程数
                          long keepAliveTime, // 存活时间
                          TimeUnit unit, // 单位
                          BlockingQueue<Runnable> workQueue,// 任务队列
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

corePoolSize:核心线程数,提交任务后首先通过核心线程执行任务,当核心线程数达到corePoolSize值的时候,会开辟新的线程执行任务。一般来说核心线程数设置的值为CPU核数,具体情况根据具体的业务来分析。

maximumPoolSize:最大线程数,包括核心线程和非核心线程。

keepAliveTime:非核心线程存活时间,当核心线程数能够执行当前任务时,非核心线程处于空闲状态,但是并不会立马消失,如果设置存活时间,则会等存活时间过之后会被回收。

unit:keepAliveTime的单位,主要包括DAYS:时间单位代表二十四小时;HOURS:时间单位代表六十分钟;MICROSECONDS:时间单位代表千分之一毫秒;MILLISECONDS:时间单位为千分之一秒;MINUTES:时间单位代表6o秒;NANOSECONDS:时间单位代表千分之一千分之一;SECONDS:时间单位代表一秒。

workQueue:存储等待执行任务的队列。

threadFactory:线程工厂,用于创建线程。

handler:拒绝策略,主要包含以下几种。

1、默认的策略:直接抛出异常

public static class AbortPolicy implements RejectedExecutionHandler {
    public AbortPolicy() { }
​
    /**
     * Always throws RejectedExecutionException.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     * @throws RejectedExecutionException always
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}

2、直接由提交任务的线程执行任务,不用去到队列中

public static class CallerRunsPolicy implements RejectedExecutionHandler {
    public CallerRunsPolicy() { }
​
    /**
     * Executes task r in the caller's thread, unless the executor
     * has been shut down, in which case the task is discarded.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            // 直接通过r来执行任务
            r.run();
        }
    }
}

3、丢弃掉阻塞队列中最靠前的任务

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    public DiscardOldestPolicy() { }
​
    /**
     * Obtains and ignores the next task that the executor
     * would otherwise execute, if one is immediately available,
     * and then retries execution of task r, unless the executor
     * is shut down, in which case task r is instead discarded.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            // 返回队里中的头部元素
            e.getQueue().poll();
            e.execute(r);
        }
    }
}

4、丢弃掉当前任务

public static class DiscardPolicy implements RejectedExecutionHandler {
    public DiscardPolicy() { }
​
    /**
     * Does nothing, which has the effect of discarding task r.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
}

二、线程池的相关状态

RUNNING:线程池运行状态,可以接收新的任务,并且可以处理阻塞队列中的任务。

SHUTDOWN:关闭状态,关闭意味着不会去接收新的任务,但是可以处理阻塞队列中已经存在的任务。

STOP:线程池处于停止状态,不会接收新的任务,同时也不会再执行阻塞队列中已经存在的任务。

TIDYING:所有的任务执行完成或者被终止处于该状态。

TERMINATED:当所有的任务终止或者被执行完毕的时候,所有的线程被清空的时候,线程池会处于该状态。

执行线程的方法:execute(),submit(),shutdown(),shutdownNow()

三、创建线程也可以使用Executors类,可以创建不同的线程池,比如:

  1. newFixedThreadPool(int nThreads): 创建一个固定大小的线程池。

  2. newCachedThreadPool(): 创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

  3. newSingleThreadExecutor(): 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证按提交顺序执行。

  4. newScheduledThreadPool(int corePoolSize): 创建一个固定大小的线程池,可以在给定的延迟后执行或定期执行任务。

  5. newSingleThreadScheduledExecutor(): 创建一个单线程化的线程池,可以在给定的延迟后执行或定期执行任务。

通过此方法创建的线程池返回的也是ThreadPoolExecutor对象,只是给定了相关的参数,比如newCachedThreadPool源码如下:

public static ExecutorService newCachedThreadPool() {
    // 返回ThreadPoolExecutor对象
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

newScheduledThreadPool线程池可以通过调度的方式进行执行,示例如下:

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
// 可以设置延迟几秒后执行任务
scheduledExecutorService.schedule(new Runnable() {
    @Override
    public void run() {
        log.info("任务执行");
    }
},2, TimeUnit.SECONDS);
​
// 间隔一秒 每三秒执行一次
/**
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);
*/
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        log.info("任务执行");
    }
},1,3,TimeUnit.SECONDS);

  • 21
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值