不同线程池的区别
Executors工厂类在Java中提供了多种便捷的线程池创建方法,每种方法创建的线程池都有其特定的使用场景和优缺点。以下是Executors工厂类提供的不同线程池的区别:
1. newFixedThreadPool(int nThreads)
特点:创建的线程池具有固定的线程数量,即参数nThreads指定的数量。当线程池中的线程数量达到核心线程数后,新的任务将被放入队列中等待执行。
使用场景:适用于执行长期任务、负载较为稳定的场景。由于线程数量固定,可以更好地控制并发度和系统资源的使用。
优缺点:优点是线程数量固定,资源消耗可控;缺点是如果任务提交速度大于任务处理速度,可能会导致任务积压在队列中,甚至可能引发内存溢出。
2. newCachedThreadPool()
特点:可以根据需要动态创建新线程的线程池。当有空闲线程时,会优先使用空闲线程执行任务;如果没有空闲线程,则创建新线程。线程在空闲超过一定时间(默认为60秒)后会被终止并移除。
使用场景:适用于执行大量短期异步任务的场景。由于线程数量不固定,可以根据任务需求动态调整,因此具有较高的灵活性。
优缺点:优点是线程数量动态调整,灵活高效;缺点是如果任务提交速度非常快,可能会创建大量线程,导致系统资源耗尽。
3. newSingleThreadExecutor()
特点:创建的线程池中只有一个线程,所有任务将按顺序在这个唯一的线程中执行。如果线程在执行任务过程中发生异常,线程池会创建一个新的线程来继续执行后续任务。
使用场景:适用于需要保证任务按顺序执行的场景,如日志记录、任务调度等。
优缺点:优点是任务按顺序执行,保证了任务之间的顺序性;缺点是如果任务执行时间较长,可能会导致后续任务等待时间较长。
4. newScheduledThreadPool(int corePoolSize)
特点:可以创建固定大小的线程池,用于调度任务执行。支持延迟执行和周期性任务调度。
使用场景:适用于需要按计划执行任务的场景,如周期性检查、定时数据备份、定时任务调度等。
优缺点:优点是支持定时和周期性任务调度,灵活性高;缺点是如果所有核心线程都在忙于执行任务,而新任务到达时会被排队等待,可能会导致任务调度延迟。
5. newWorkStealingPool()(注意:此线程池在JDK 1.8中引入,不属于Executors的直接方法,但常作为线程池的一种提及)
特点:基于ForkJoinPool实现的线程池,拥有多个任务队列,可以减少连接数。创建当前可用CPU数量的线程来并行执行。
使用场景:适用于大耗时的操作,可以并行执行以提高性能。
优缺点:优点是能够充分利用多核CPU资源,提高并行性能;缺点是对于小任务或任务之间依赖关系复杂的场景,可能不是最佳选择。
自定义线程池的核心参数和工作原理
自定义线程池在Java中主要通过ThreadPoolExecutor
类来实现,其核心参数和工作原理对于理解和使用线程池至关重要。
核心参数
自定义线程池时,ThreadPoolExecutor
的构造函数允许传入多个参数来配置线程池的行为,这些核心参数包括:
corePoolSize(核心线程池大小):
线程池中始终保持的活动线程数量。
即使这些线程处于空闲状态,也不会被销毁,除非设置了允许核心线程超时。
maximumPoolSize(最大线程池大小):
线程池中允许的最大线程数量。
当线程池中的线程数量达到这个值时,新的任务会被放入等待队列中,或者根据拒绝策略进行处理。
keepAliveTime(线程空闲时间):
当线程池中的线程数量超过核心线程池大小时,多余的空闲线程在多长时间内会被销毁。
这个参数仅对非核心线程有效。
unit(线程空闲时间的时间单位):
keepAliveTime
参数的时间单位,如TimeUnit.SECONDS
、TimeUnit.MILLISECONDS
等。
workQueue(等待队列):
用于存放等待执行的任务。
常见的等待队列包括
ArrayBlockingQueue
、LinkedBlockingQueue
、SynchronousQueue
等。
threadFactory(线程工厂):
用于创建新的线程。
可以通过自定义线程工厂来设置线程的优先级、是否为守护线程、线程名称等属性。
handler(拒绝策略):
用于在任务无法被执行时的处理方式。
常见的拒绝策略包括
AbortPolicy
(抛出异常)、CallerRunsPolicy
(由提交任务的线程执行该任务)、DiscardPolicy
(丢弃任务)、DiscardOldestPolicy
(丢弃队列中最早的任务)等。
工作原理
自定义线程池的工作原理可以概括为以下几个步骤:
任务提交:
当有任务需要执行时,它会被提交到线程池的等待队列中。
线程分配:
线程池中的工作线程会不断从等待队列中取出任务并执行。
如果当前线程数小于核心线程数,线程池会创建新的核心线程来执行任务。
如果当前线程数已达到核心线程数,但任务队列未满,任务会被放入队列中等待执行。
如果当前线程数已达到最大线程数,且任务队列已满,则根据拒绝策略处理新任务。
线程管理:
线程池会根据任务的提交情况和线程的状态来动态地调整线程的数量。
当线程空闲时间超过
keepAliveTime
时(仅对非核心线程有效),多余的线程会被销毁。线程池中的线程数量会在核心线程数和最大线程数之间动态调整。
任务执行:
工作线程从任务队列中获取任务并执行。
任务执行完毕后,工作线程会回到线程池中等待下一个任务的到来。
线程池关闭:
可以通过调用线程池的
shutdown()
方法来关闭线程池。关闭线程池后,线程池将不再接受新的任务,但会继续执行队列中等待的任务。
当所有任务都执行完毕后,线程池中的线程将被销毁。
综上所述,自定义线程池的核心参数和工作原理对于理解和使用线程池至关重要。通过合理配置这些参数,可以创建出符合业务需求的线程池,从而提高程序的性能和响应速度。
评论区