Java线程池详解

介绍

Java线程池(Executor Framework)是Java并发包java.util.concurrent提供的一个框架,用于管理一组工作线程(线程池),通过重用现有的线程而不是为每个任务创建新线程,来减少线程创建和销毁的开销,从而提高程序性能。

线程池的状态

Java线程池中的ThreadPoolExecutor类定义了线程池的几种状态:

  • RUNNING:接受新任务,处理排队的任务。
  • SHUTDOWN:不接受新任务,但处理已排队的任务。
  • STOP:不接受新任务,不处理已排队的任务,并中断正在处理的任务。
  • TIDYING:所有任务都终止了,workerCount为0,线程池状态将变为TIDYING,然后执行terminated()方法。
  • TERMINATED:terminated()方法完成执行后的状态。

创建线程池的几种方式

  • Executors.newFixedThreadPool(int nThreads):创建一个固定大小的线程池。
  • Executors.newCachedThreadPool():创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • Executors.newSingleThreadExecutor():创建一个单线程的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
  • Executors.newScheduledThreadPool(int corePoolSize):创建一个定长线程池,支持定时及周期性任务执行。
    ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler):通过ThreadPoolExecutor类直接创建,参数灵活,可自定义线程池的大小、任务队列、拒绝策略等。

线程池各参数的说明

  • corePoolSize:核心线程数,即使它们空闲,线程池也会保持线程的数量。
  • maximumPoolSize:最大线程数,线程池允许的最大线程数。
  • keepAliveTime:当线程数大于核心时,这是多余空闲线程在终止前等待新任务的最长时间。
  • unit:keepAliveTime参数的时间单位。
  • workQueue:用于存放任务的阻塞队列。
  • threadFactory:用于创建新线程的工厂。
  • handler:由于超出线程范围和队列容量而使任务被拒绝的处理器。
import java.util.concurrent.*;  
  
public class ThreadPoolExample {  
    public static void main(String[] args) {  
        // 示例:使用ThreadPoolExecutor创建线程池  
        ThreadPoolExecutor executor = new ThreadPoolExecutor(  
                2,          // 核心线程数  
                5,          // 最大线程数  
                10,         // 非核心线程闲置超时时间  
                TimeUnit.SECONDS,  
                new LinkedBlockingQueue<>(10), // 阻塞队列  
                Executors.defaultThreadFactory(),  
                new ThreadPoolExecutor.AbortPolicy() // 拒绝策略  
        );  
  
        // 提交任务  
        for (int i = 0; i < 20; i++) {  
            int taskId =i;
			executor.execute(() -> {
			System.out.println(Thread.currentThread().getName() + " is processing " + taskId);
			try {
				Thread.sleep(1000);
				} catch (InterruptedException e) {
					Thread.currentThread().interrupt();
				}
			});
		}

// 关闭线程池  
     executor.shutdown(); // 优雅关闭  
    // executor.awaitTermination(60, TimeUnit.SECONDS); // 等待线程池中的任务完成  

    // 或者立即尝试停止  
    // executor.shutdownNow();  

    // 注意:实际使用中,应该根据业务场景选择是否等待线程池中的任务完成  
}

在这个示例中,我们创建了一个ThreadPoolExecutor实例,并配置了核心线程数、最大线程数、非核心线程的超时时间、任务队列以及拒绝策略。然后,我们提交了20个任务到线程池。在实际应用中,你可能需要调用shutdown()shutdownNow()来关闭线程池,具体取决于你的需求。如果你希望线程池中的任务都完成后再关闭,应该调用shutdown()并可能使用awaitTermination()来等待。如果你需要立即停止所有任务,可以调用shutdownNow()

注意,在调用shutdown()shutdownNow()之后,应该避免再向线程池提交任务,因为这些任务可能会被拒绝。同时,如果线程池中的任务执行了中断敏感的操作(如调用了Thread.sleep()),那么在调用shutdownNow()时,这些任务应该能够响应中断,并尽早退出。

阻塞队列Handle有哪几种?

  • ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
  • LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列(但大小默认为Integer.MAX_VALUE)。
  • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,反之亦然。
  • PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。

拒绝策略有哪几种?

  • ThreadPoolExecutor.AbortPolicy:默认策略,直接抛出RejectedExecutionException。
  • ThreadPoolExecutor.CallerRunsPolicy:在调用者线程中直接运行被拒绝的任务。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后尝试重新提交被拒绝的任务。
  • ThreadPoolExecutor.DiscardPolicy:不处理被拒绝的任务,直接丢弃。

停止线程池的方式与区别

  • shutdown():启动线程池的关闭序列,不再接受新任务,但会继续处理队列中的任务。
  • shutdownNow():尝试停止所有正在执行的活动任务,停止处理正在等待的任务,并返回等待执行的任务列表。

区别:shutdown()是平滑地关闭线程池,等待正在执行的任务完成;而shutdownNow()是尝试立即停止所有任务,包括正在执行的任务,并尝试返回那些还未开始执行的任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值