Java线程池的使用

概述:在一些场景下,我们使用多线程去解决一些高并发的问题,实现起来很方便。但是会有一些问题,如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。

那么,有没有一种办法可以使得线程复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?
答案是有的,通过线程池可以达到这样的效果,线程池最核心的类是ThreadPoolExecutor,那就先从这个类说起吧。

1. ThreadPoolExecutor类中四个构造方法

首先捋一下ThreadPoolExecutor类的继承关系:
在这里插入图片描述
从图中可以看出,ThreadPoolExecutor继承了AbstractExecutorService类,而AbstractExecutorService实现了ExecutorService接口,ExecutorService接口又继承了Executor接口,Executor接口中只定义了一个方法void execute(Runnable command)。

  • 该类主要有四个构造方法,先来看一下源码,以下是构造方法1:
    /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters and default thread factory and rejected execution handler.
     * It may be more convenient to use one of the {@link Executors} factory
     * methods instead of this general purpose constructor.
     * 创建一个给定初始化参数、默认线程工厂和默认拒绝执行处理程序的ThreadPoolExecutor。
     * 使用Executors工厂方法之一而不是这个通用构造方法可能更方便。
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set  
     * 线程池核心线程数,如果空闲也一直保持在线程池中的线程数,除非设置了
     * allowCoreThreadTimeOut属性值
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * 线程池最大能容忍的线程数
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * 表示线程没有任务执行时最多保持多久时间会销毁
     * @param unit the time unit for the {@code keepAliveTime} argument
     * 表示keepAliveTime的时间单位,有7种值,可以从TimeUnit类种获取
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * 表示一个阻塞队列,用来存储等待执行的任务,常用有3种队列:
     * ArrayBlockingQueue
     * LinkedBlockingQueue
     * SynchronousQueue
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
  • 构造方法2,相比构造方法1多了一个可传参数threadFactory:
 /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters and default rejected execution handler.
     * 创建一个给定初始化参数和默认拒绝执行处理程序的ThreadPoolExecutor
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * 线程池核心线程数,如果空闲也一直保持在线程池中的线程数,除非设置了
     * allowCoreThreadTimeOut属性值
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * 最大能容忍的线程数
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * 表示线程没有任务执行时最多保持多久时间将会终止,直至达到不小于核心线程数
     * @param unit the time unit for the {@code keepAliveTime} argument
     * keepAliveTime的时间单位,有7种值,可从TimeUnit类中获取
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * 一个阻塞队列,用来存储等待执行的任务,一般有以下3种:
     * ArrayBlockingQueue
     * LinkedBlockingQueue
     * SynchronousQueue
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * 线程工厂,当executor创建一个新线程时用该工厂创建
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
  • 构造方法3,相比构造方法1多了一个可传入参数rejectedExecutionHandler:
/**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters and default thread factory.
     * 创建一个给定初始化参数和默认的线程工厂的ThreadPoolExecutor
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * 线程池核心线程数,如果空闲也一直保持在线程池中的线程数,除非设置了
     * allowCoreThreadTimeOut属性值
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * 线程池中最大容忍线程数
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * 表示线程没有任务执行时最多保持多久时间将会终止,直至达到不小于核心线程数
     * @param unit the time unit for the {@code keepAliveTime} argument
     * keepAliveTime的时间单位,有7种值,可从TimeUnit类中获取
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * 一个阻塞队列,用来存储等待执行的任务,一般有以下3种:
     * ArrayBlockingQueue
     * LinkedBlockingQueue
     * SynchronousQueue
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * handler在执行被阻止时使用,因为达到了线程边界和队列容量
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code handler} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
  • 构造方法4,相比构造方法1多了两个可传入参数threadFactory和rejectedExecutionHandler:
/**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     * 创建一个给定初始化参数的ThreadPoolExecutor
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * 线程池核心线程数,如果空闲也一直保持在线程池中的线程数,除非设置了
     * allowCoreThreadTimeOut属性值
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * 线程池中最大容忍线程数
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * 表示线程没有任务执行时最多保持多久时间将会终止,直至达到不小于核心线程数
     * @param unit the time unit for the {@code keepAliveTime} argument
     * keepAliveTime的时间单位,有7种值,可从TimeUnit类中获取
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * 一个阻塞队列,用来存储等待执行的任务,一般有以下3种:
     * ArrayBlockingQueue
     * LinkedBlockingQueue
     * SynchronousQueue
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * 线程工厂,当executor创建一个新线程时用该工厂创建
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * handler在执行被阻止时使用,因为达到了线程边界和队列容量
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

2. 构造方法中参数的作用

  • corePoolSize: 核心池线程数,默认情况下线程池中的线程数为0(除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,是预创建线程的意思),当有任务到来之后,就会创建一个线程去执行任务,当线程池中的线程数达到corePoolSize后,再新来任务就会放到缓存队列当中;
  • maximumPoolSize: 线程池中最大容忍线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建的线程数;
  • keepAliveTime: 表示线程空闲后保持多久时间会终止。默认情况下,当前线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize值。但是如果调用了allowCoreThreadTimeOut(true)方法,在线线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
  • unit: 参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性,分别是:
    TimeUnit.DAYS;//天
    TimeUnit.HOURS;//小时
    TimeUnit.MINUTES;//分钟
    TimeUnit.SECONDS;//秒
    TimeUnit.MILLISECONDS;//毫秒
    TimeUnit.MICROSECONDS;//微妙
    TimeUnit.NANOSECONDS;//纳秒
  • workQueue: 一个阻塞队列,用来存储等待执行的任务,这个参数会对线程池的运行过程产生重大影响,一般有以下4种选择:
    ArrayBlockingQueue
    PriorityBlockingQueue
    LinkedBlockingQueue
    SynchronousQueue
    前两个使用比较少,常用的是LinkedBlockingQueue 和 SynchronousQueue;
  • threadFactory: 线程工厂,主要用来创建新的线程;
  • handler: 拒绝执行处理器(RejectedExecutionHandler),在执行被阻止时使用,因为达到了线程边界和队列容量,有以下4种选择:
    ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。
    ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
    ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

3. ThreadPoolExecutor类中其他几个重要的方法

  • execute(): 这个方法是在Executor接口中声明的,只是在ThreadPoolExecutor类中进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,交由线程池去执行;
  • submit(): 这个方法是在ExecutorService中声明的,在AbstractExecutorService类中就已经有了具体的实现,并没有在ThreadPoolExecutor中进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同的是,它能够返回任务执行的结果,返回结果类型为FutureTask;
  • shutdown(): 用来关闭线程池的,调用这个方法后,就不能在线程池添加任何任务,否则会报RejectedExecutionException异常,但是线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成后才会退出;
  • shutdownNow(): 关闭线程池,迫使线程池中所有线程执行退出,从而让主程序正常退出。但并不代表线程池一定能立即退出,因为终止线程的方法是通过调用Thread.interrupt()方法实现的,如果线程中没有sleep、wait、Condition、定时锁等应用,interrupt()方法是无法中断当前线程的,它可能必须要等待所有正在执行的任务都执行完成了才能退出;

4. Executors工具类的使用

Executors类中提供了一些获取线程池的静态方法,以下是几个常用的方法:

  • newFixedThreadPool 固定大小线程池,简单来说就是每次提交一个任务就会创建一个线程,直到线程达到线程池的核心数大小,再来任务就会放到缓存队列中:
/**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue.  At any point, at most
     * {@code nThreads} threads will be active processing tasks.
     * If additional tasks are submitted when all threads are active,
     * they will wait in the queue until a thread is available.
     * If any thread terminates due to a failure during execution
     * prior to shutdown, a new one will take its place if needed to
     * execute subsequent tasks.  The threads in the pool will exist
     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
     * 创建一个线程池,该线程池会重复使用在共享的无界队列中运行的固定数量的线程。 在任何时候,
     * 最多nThreads线程将是活动的处理任务。如果在所有线程都处于活动状态时提交了其他任务,
     * 则它们将在队列中等待,直到线程空闲可用。如果任何一个线程由于在关闭之前执行期间中出现故障而终止,
     * 那么如果需要执行后续任务,则新的线程将会取代它。线程池中的线程将一直存在,直到它被显式的shutdown。
     * @param nThreads the number of threads in the pool
     * 线程池的线程数
     * @return the newly created thread pool
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
  • newSingleThreadExecutor 单线程执行的线程池,它相当于单线程 串行执行所有任务。如果这个唯一的线程因为异常而终止,那么会有一个新的线程来替代它。该线程池能保证所有任务的执行顺序是按照任务的提交顺序执行。值得注意的是:该线程从效果上和 newFixedThreadPool(1) 是一样的,但是返回时有一些区别,该线程池返回对象是经过FinalizableDelegatedExecutorService进行了包装,目的是为了在垃圾回收前销毁线程。
/**
     * Creates an Executor that uses a single worker thread operating
     * off an unbounded queue. (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * {@code newFixedThreadPool(1)} the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     * 创建一个Executor,它使用一个在无界队列中运行的工作线程。 
     *(但请注意,如果此单个线程由于在关闭之前执行期间出现故障而终止,则在需要执行后续任务时将使用新的线程。)
     * 保证任务顺序执行,并且在任何给定的时间内不会有多个任务处于活动状态。 
     * 与其他等效的例如:newFixedThreadPool(1) 不同,它保证返回的执行程序不可重新配置以使用其他线程。
     * @return the newly created single-threaded Executor
     */
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
static class FinalizableDelegatedExecutorService
        extends DelegatedExecutorService {
        FinalizableDelegatedExecutorService(ExecutorService executor) {
            super(executor);
        }
        //垃圾收集前会进行shutdown操作
        protected void finalize() {
            super.shutdown();
        }
    }
  • newCachedThreadPool 线程可缓存的线程池,corePoolSize设置为0,maximumPoolSize设置为Integer.MAX_VALUE
/**
     * Creates a thread pool that creates new threads as needed, but
     * will reuse previously constructed threads when they are
     * available.  These pools will typically improve the performance
     * of programs that execute many short-lived asynchronous tasks.
     * Calls to {@code execute} will reuse previously constructed
     * threads if available. If no existing thread is available, a new
     * thread will be created and added to the pool. Threads that have
     * not been used for sixty seconds are terminated and removed from
     * the cache. Thus, a pool that remains idle for long enough will
     * not consume any resources. Note that pools with similar
     * properties but different details (for example, timeout parameters)
     * may be created using {@link ThreadPoolExecutor} constructors.
     * 创建一个可根据需要来创建新线程的线程池,但在它们可用时将重复使用以前构造好的线程。 
     * 该线程池通常会提高执行许多短期异步任务的程序的性能。对execute的调用将重复使用以前构造好的线程(如果可用的话)。 
     * 如果没有可用的现有线程,则将创建一个新线程并将其添加到池中。未使用(空闲)60秒的线程将终止并从缓存中删除。 
     * 因此,长时间闲置的池不会消耗任何资源。请注意,也可以使用ThreadPoolExecutor构造方法自定义
     * 创建具有相似属性但不同详细信息的池(例如,超时参数)。
     * @return the newly created thread pool
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
  • newScheduledThreadPool 创建一个ScheduledExecutorService线程池,该线程池可以实现定时、周期性执行任务,具体方法可以参考ScheduledExecutorService接口的实现类ScheduledThreadPoolExecutor;
	/**
     * Creates a thread pool that can schedule commands to run after a
     * given delay, or to execute periodically.
     * 创建一个线程池,可以调度命令,以在给定的延迟时间后运行,或者定期执行。
     * @param corePoolSize the number of threads to keep in the pool,
     * even if they are idle
     * 保持在线程池中的核心线程数,请注意,即使这些线程处于空闲状态也一直保持在线程池中
     * @return a newly created scheduled thread pool
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
     */
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

5. 项目中的实际运用

在实际的项目开发中,遇到需要异步处理的逻辑,可以使用Executors工具类去实现一个线程池(最好自己定义ThreadPoolExecutor来初始化一个线程池),然后提交一个任务去执行,我们可以根据不通的业务场景封装不同的线程池单例类,这样可以在不同场景使用相应的线程池(统一维护、管理、监控),以下是对Executors中部分方法封装的线程池单例类代码(通过内部类实现的单例模式):
为什么可以使用内部类实现单例模式?
JVM必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待,只有在活动线程执行完对类的初始化操作之后,才会通知正在等待的其他线程,所以可以利用静态内部类实现线程安全的单例模式。

/**
 * @Author: Helon
 * @Description: 常用的三种线程池,单例获取
 * @Data: Created in 2018/3/23 23:16
 * @Modified By:
 */
public class ThreadPoolSingleton {
    /**核心线程数,
     * 经验值设置,如果是CPU计算密集型应用设置为N+1或jdk1.8以上可设置为2N
     * 如果是IO密集型应用设置为N/(1-阻塞系数),阻塞系数一般为0.8~0.9之间(也可直接取0.8或0.9)其中N表示当前服务器的CPU核数
     */
    private static final int CORETHREADS = 10;

    /**
     * 1.默认创建的线程池corePoolSize和maximumPoolSize值是相等的;
     * 2.默认使用的是LinkedBlockingQueue队列,队列长度未指定,默认大小为Integer.MAX_VALUE
     * 3.默认keepAliveTime=0L,表示当前线程数大于corePoolSize时,空闲时间为0,即立即回收
     * 推荐使用
     */
    private static class NewFixedThreadPoolInstance {
        private static ExecutorService instance = Executors.newFixedThreadPool(CORETHREADS);
    }
    /**
     *newFixedThreadPool获取单例
     *
     */
    public static ExecutorService newFixedThreadPool(){
        return NewFixedThreadPoolInstance.instance;
    }
    
    /**
     * 1.默认创建的线程池corePoolSize和maximumPoolSize值是相等的,并且大小都为1;
     * 2.默认使用的是LinkedBlockingQueue队列,队列长度未指定,默认大小为Integer.MAX_VALUE
     * 3.默认keepAliveTime=0L,表示当前线程数大于corePoolSize时,空闲时间为0,即只要空闲立即销毁回收
     */
    private static class NewSingleThreadExecutorInstance {
        private static ExecutorService instance = Executors.newSingleThreadExecutor();
    }
    /**
     *newSingleThreadExecutor获取单例
     *
     */
    public static ExecutorService newSingleThreadPool(){
        return NewSingleThreadExecutorInstance.instance;
    }
    
    /**
     * 1.默认创建的线程池corePoolSize为0,,maximumPoolSize值为Integer.MAX_VALUE;
     * 2.默认使用的是SynchronousQueue队列,表示来了任务就创建线程运行
     * 3.默认keepAliveTime=60L,单位是秒,表示当线程空闲超过60秒,就销毁线程
     */
    private static class NewCachedThreadPoolInstance {
        private static ExecutorService instance = Executors.newCachedThreadPool();
    }
    
    /**
     *newCachedThreadPool获取单例
     *
     */
    public static ExecutorService newCachedThreadPool(){
        return NewCachedThreadPoolInstance.instance;
    }
	
	private ThreadPoolSingleton(){}
}
  • 这里对核心线程数简单说明一下,有个经验值:如果是CPU计算密集型应用(如:计算大量文件的大小),核心线程数=N+1,如果使用的jdk1.8及以上的可设置为2N(因为高版本jdk增加了并行计算);如果是IO密集型应用(如:大量网络传输,数据库访问等IO访问频繁的应用),核心线程数=N/(1-阻塞系数),这个阻塞系数一般为0.8~0.9。以上是经验值,并非绝对的,还需要根据实际情况以及实际业务来调整;
  • 到这里线程池的基本用法已经说的差不多了,然而实际项目中可能需要实时的了解一下线程池任务执行情况,这样应该怎么处理呢?我在项目中写了一个轮询查看线程池使用情况的任务,以下是我的实现代码:
/**
 * @Author: Helon
 * @Description: 线程池定时监控任务
 * @Data: Created in 2018/4/16 17:31
 * @Modified By:
 */
@Component
public class ThreadPoolMonitorTask {

    /***
     * 内部类初始化executor
     */
    private static class InitExecutorService {
        /**从线程池中获取newFixedThreadPool*/
        private static ExecutorService executorService = ThreadPoolSingleton.newFixedThreadPool();
    }

    /**
     * @Author: Helon
     * @Description: 初始化10s后开始执行,每隔30秒监控一次
     * @Data: 2018/4/16 17:50
     * @Modified By:
     */
    @Scheduled(initialDelay = 10000L, fixedDelay = 30000L)
    public void check() {
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor)InitExecutorService.executorService;
        LogUtil.KAFKA.info("[线程池定时监控]-核心池大小:{},最大线程数:{},当前线程数:{},当前活动线程数:{}",threadPoolExecutor.getCorePoolSize(),
                threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getPoolSize(), threadPoolExecutor.getActiveCount());
        LogUtil.KAFKA.info("[线程池定时监控]-总任务数:{},已经执行完毕的任务数:{},出现过最大的线程数:{}",threadPoolExecutor.getTaskCount(),
                threadPoolExecutor.getCompletedTaskCount(), threadPoolExecutor.getLargestPoolSize());
    }
}

好了,以上就是我对线程池的总结与使用,如有疑义的地方欢迎批评指正,一起交流学习。

标题SpringBoot智能在线预约挂号系统研究AI换标题第1章引言介绍智能在线预约挂号系统的研究背景、意义、国内外研究现状及论文创新点。1.1研究背景与意义阐述智能在线预约挂号系统对提升医疗服务效率的重要性。1.2国内外研究现状分析国内外智能在线预约挂号系统的研究与应用情况。1.3研究方法及创新点概述本文采用的技术路线、研究方法及主要创新点。第2章相关理论总结智能在线预约挂号系统相关理论,包括系统架构、开发技术等。2.1系统架构设计理论介绍系统架构设计的基本原则和常用方法。2.2SpringBoot开发框架理论阐述SpringBoot框架的特点、优势及其在系统开发中的应用。2.3数据库设计与管理理论介绍数据库设计原则、数据模型及数据库管理系统。2.4网络安全与数据保护理论讨论网络安全威胁、数据保护技术及其在系统中的应用。第3章SpringBoot智能在线预约挂号系统设计详细介绍系统的设计方案,包括功能模块划分、数据库设计等。3.1系统功能模块设计划分系统功能模块,如用户管理、挂号管理、医生排班等。3.2数据库设计与实现设计数据库表结构,确定字段类型、主键及外键关系。3.3用户界面设计设计用户友好的界面,提升用户体验。3.4系统安全设计阐述系统安全策略,包括用户认证、数据加密等。第4章系统实现与测试介绍系统的实现过程,包括编码、测试及优化等。4.1系统编码实现采用SpringBoot框架进行系统编码实现。4.2系统测试方法介绍系统测试的方法、步骤及测试用例设计。4.3系统性能测试与分析对系统进行性能测试,分析测试结果并提出优化建议。4.4系统优化与改进根据测试结果对系统进行优化和改进,提升系统性能。第5章研究结果呈现系统实现后的效果,包括功能实现、性能提升等。5.1系统功能实现效果展示系统各功能模块的实现效果,如挂号成功界面等。5.2系统性能提升效果对比优化前后的系统性能
在金融行业中,对信用风险的判断是核心环节之一,其结果对机构的信贷政策和风险控制策略有直接影响。本文将围绕如何借助机器学习方法,尤其是Sklearn工具包,建立用于判断信用状况的预测系统。文中将涵盖逻辑回归、支持向量机等常见方法,并通过实际操作流程进行说明。 一、机器学习基本概念 机器学习属于人工智能的子领域,其基本理念是通过数据自动学习规律,而非依赖人工设定规则。在信贷分析中,该技术可用于挖掘历史数据中的潜在规律,进而对未来的信用表现进行预测。 二、Sklearn工具包概述 Sklearn(Scikit-learn)是Python语言中广泛使用的机器学习模块,提供多种数据处理和建模功能。它简化了数据清洗、特征提取、模型构建、验证与优化等流程,是数据科学项目中的常用工具。 三、逻辑回归模型 逻辑回归是一种常用于分类任务的线性模型,特别适用于二类问题。在信用评估中,该模型可用于判断借款人是否可能违约。其通过逻辑函数将输出映射为0到1之间的概率值,从而表示违约的可能性。 四、支持向量机模型 支持向量机是一种用于监督学习的算法,适用于数据维度高、样本量小的情况。在信用分析中,该方法能够通过寻找最佳分割面,区分违约与非违约客户。通过选用不同核函数,可应对复杂的非线性关系,提升预测精度。 五、数据预处理步骤 在建模前,需对原始数据进行清理与转换,包括处理缺失值、识别异常点、标准化数值、筛选有效特征等。对于信用评分,常见的输入变量包括收入水平、负债比例、信用历史记录、职业稳定性等。预处理有助于减少噪声干扰,增强模型的适应性。 六、模型构建与验证 借助Sklearn,可以将数据集划分为训练集和测试集,并通过交叉验证调整参数以提升模型性能。常用评估指标包括准确率、召回率、F1值以及AUC-ROC曲线。在处理不平衡数据时,应关注模型的召回率与特异性。 七、集成学习方法 为提升模型预测能力,可采用集成策略,如结合多个模型的预测结果。这有助于降低单一模型的偏差与方差,增强整体预测的稳定性与准确性。 综上,基于机器学习的信用评估系统可通过Sklearn中的多种算法,结合合理的数据处理与模型优化,实现对借款人信用状况的精准判断。在实际应用中,需持续调整模型以适应市场变化,保障预测结果的长期有效性。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
<think>好的,我需要回答用户关于如何在Java使用线程池的问题,包括示例代码和最佳实践。首先,我应该回顾用户提供的引用内容,看看有没有相关的信息可以利用。 根据引用[1],提到了Java线程池使用实例、最佳实践以及代码示例。引用[2]讨论了为什么使用线程池、如何使用以及遇到的坑。引用[3]则集中在最佳实践和异常处理方面。这些引用应该能提供足够的信息来构建回答。 首先,我需要解释线程池的基本概念和为什么要使用线程池,比如资源复用、控制并发数、管理线程生命周期等。然后,介绍Java中创建线程池方法,特别是通过Executors工厂类提供的几种常见线程池类型,比如FixedThreadPool、CachedThreadPool、SingleThreadExecutor等,但也要提到推荐直接使用ThreadPoolExecutor来创建,以便灵活地控制参数,避免资源耗尽的风险,这点在引用[3]中有提到。 接下来,给出一个示例代码。根据引用[1]中的示例,可能需要展示如何通过ThreadPoolExecutor来创建线程池,设置核心线程数、最大线程数、队列容量等参数,并演示如何提交任务。同时,需要强调在阿里巴巴开发规范中推荐手动创建线程池,而不是使用Executors,这点可能来自引用[3]中的最佳实践。 然后,讨论最佳实践,比如合理配置线程数、使用有界队列、处理未捕获异常、正确关闭线程池等。这些内容在引用[3]中有涉及,比如异常处理和分析的重要性,以及关闭线程池方法。 此外,要注意线程池的任务拒绝策略,如AbortPolicy、CallerRunsPolicy等,并说明在不同场景下如何选择合适的策略。这部分可能需要结合引用[2]中提到的使用过程中遇到的坑。 最后,生成相关问题,可能包括线程池的参数配置、不同线程池类型的区别、如何监控线程池状态、常见的线程池问题排查等,确保问题与用户查询内容相关,并帮助深化理解。 需要确保回答结构清晰,分步骤说明,代码正确,并且引用正确的位置。例如,在提到线程池参数配置时,引用[3]中的最佳实践;在提到任务拒绝策略时,引用[2]中的实际应用经验。 现在需要将以上思考整理成中文回答,确保符合用户要求的格式,使用正确的LaTeX语法,并在适当的位置添加引用标识。</think>### 如何在Java使用线程池? #### 1. **线程池的作用与优势** - **资源复用**:避免频繁创建/销毁线程,提升性能[^2]。 - **控制并发**:通过核心线程数、最大线程数限制资源占用[^3]。 - **任务管理**:使用队列缓冲任务,支持拒绝策略处理过载[^1]。 #### 2. **创建线程池** Java推荐通过`ThreadPoolExecutor`手动配置参数(而非`Executors`工厂类,避免潜在风险)[^3]: ```java int corePoolSize = 5; // 核心线程数 int maxPoolSize = 10; // 最大线程数 long keepAliveTime = 60L; // 空闲线程存活时间(秒) BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100); // 有界队列 ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.AbortPolicy() // 默认拒绝策略:直接抛出异常 ); ``` #### 3. **提交任务** - 使用`execute()`提交`Runnable`任务: ```java executor.execute(() -> { System.out.println("Task executed by " + Thread.currentThread().getName()); }); ``` - 使用`submit()`提交`Callable`任务(可获取返回值): ```java Future<String> future = executor.submit(() -> { return "Result from thread " + Thread.currentThread().getName(); }); System.out.println(future.get()); // 阻塞获取结果 ``` #### 4. **最佳实践** - **参数配置**: - CPU密集型任务:核心线程数 ≈ CPU核心数[^3]。 - I/O密集型任务:核心线程数可适当增加(如2倍CPU核心数)。 - 使用有界队列避免内存溢出[^3]。 - **异常处理**: ```java executor.setRejectedExecutionHandler((r, executor) -> { // 自定义拒绝策略,如记录日志或降级处理 }); // 任务内捕获异常 executor.execute(() -> { try { // 业务逻辑 } catch (Exception e) { // 记录异常 } }); ``` - **关闭线程池**: ```java executor.shutdown(); // 等待已提交任务完成 // executor.shutdownNow(); // 立即终止所有任务(慎用) ``` #### 5. **常用线程池类型** - **FixedThreadPool**:固定线程数,适用于负载较重的场景。 ```java ExecutorService fixedPool = Executors.newFixedThreadPool(5); ``` - **CachedThreadPool**:弹性线程数,适合短时异步任务[^1]。 - **ScheduledThreadPool**:支持定时/周期性任务。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值