开发者社区 问答 正文

【百问百答】Java开发手册灵魂15问之为什么禁止使用Executors创建线程池

1. 什么是线程池

2. 为什么要使用线程池

3. 线程池有什么作用

4. 说说常见线程池newSingleThreadExecutor及使用场景

5. 说说常见线程池newFixedThreadPool及使用场景

6. 说说常见线程池newCachedThreadPool及使用场景

7. 说说常见线程池newScheduledThreadPool及使用场景

8. 简述线程池中重要的参数corePoolSize

9. 简述线程池中重要的参数maximumPoolSize

10. 简述线程池中重要的参数keepAliveTime

11. 简述线程池中重要的参数util

12. 简述线程池中重要的参数workQueue

13. 简述线程池中重要的参数threadFactory

14. 简述线程池中重要的参数handler

15. 系统无法处理过多的请求时,应该采取策略是什么

16. 在Java语言中,提供了什么JDK借口来提供拒绝任务处理自定义实现

17. 在Java语言中,线程池ThreadPoolExecutor中提供了几种处理策略

18. 说说线程池的拒绝策略AbortPolicy策略

19. 说说线程池的拒绝策略CallerRunsPolicy 策略

20. 说说线程池的拒绝策略DiscardOleddestPolicy策略

21. 说说线程池的拒绝策略DiscardPolicy策略

22. 说说线程池的拒绝策略如何自定义

23. 在Java语言开发中执行任务、提交任务JDK提供了什么方法实现

24. execute和submit的区别

25. 简述线程池newSingleThreadExecutor的使用场景

26. 简述线程池newFixedThreadPool的使用场景

27. 简述线程池newCachedThreadPool的使用场景

28. 简述线程池newScheduledThreadPool的使用场景

29. 简述线程池newWorkStealingPool的使用场景

30. 线程池的关闭在Java语言中如何实现

31. 简述Java语言中关闭线程池的方法shutdownNow

32. 简述Java语言中关闭线程池的方法shutdown

33. IO密集型任务,初始化线程池时线程数的选择

34. CPU密集型任务,初始化线程池时线程数的选择

35. 描述线程池工作队列ArrayBlockingQueue

36. 描述线程池工作队列LinkedBlockingQueue

37. 简述newFixedThreadPool使用的什么工作队列

38. 描述线程池工作队列SynchronousQueue

39. 简述newCachedThreadPool使用的什么工作队列

40. 描述线程池工作队列PriorityBlockingQueue

41. 简述Java语言中Executors的使用

42. Executors 的创建线程池的方法,创建出来的线程池都实现了什么接口

43. Executors为什么存在缺陷

44. 为什么不允许使用Executors创建线程池

45. 如何创建合理的自定义线程池

46. 代码描述ThreadPoolExecutor 的构造函数来自己创建线程池实例

47. 简述常用开源类库创建线程池

展开
收起
huc_逆天 2021-01-15 10:47:43 2617 分享 版权
阿里云 AI 助理回答
  1. 线程池:线程池是一种基于池化概念的多线程处理形式,它管理多个线程,允许在需要时重用这些线程而不是为每个新任务创建新线程。这可以减少线程创建和销毁的开销,提高响应速度和整体性能。

  2. 为什么要使用线程池:主要目的是为了提高系统资源的利用率、控制运行时的系统资源(如内存和CPU)、管理线程的生命周期、简化并发编程的复杂度以及提高系统的可维护性。

  3. 线程池的作用:包括但不限于复用线程、控制最大并发数、管理线程的创建与销毁、提供定时执行任务的能力、实现任务队列及拒绝策略等。

  4. newSingleThreadExecutor:这是一个只使用一个工作线程的线程池,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。适用于需要保证顺序执行各个任务的场景,比如单线程事件处理。

  5. newFixedThreadPool:创建固定大小的线程池,每次提交的任务都会分配给一个线程执行,直到所有线程都在执行任务。如果此时还有新的任务提交,则会进入等待队列中排队。适用于负载较稳定的并行任务处理,如数据库连接池。

  6. newCachedThreadPool:根据需要创建新线程的线程池,如果线程空闲超过一定时间则会被回收。适用于执行很多短期异步任务的场景,如网页服务器处理请求。

  7. newScheduledThreadPool:支持定时及周期性任务执行的线程池。适用于需要执行定时任务或周期性任务的场景,如定时数据同步、定时清理缓存等。

  8. corePoolSize:线程池的核心线程数,即使线程空闲也不会被销毁,除非设置了allowCoreThreadTimeOut为true。

  9. maximumPoolSize:线程池能够容纳的最大线程数,包括核心线程和非核心线程。

  10. keepAliveTime:非核心线程闲置时的超时时长,超过这个时间就会被终止。

  11. util:此处可能是指TimeUnit,用于指定keepAliveTime的时间单位,如秒、毫秒等。

  12. workQueue:任务队列,用于存储待处理的任务,有多种类型,如无界队列LinkedBlockingQueue、有界队列ArrayBlockingQueue、直接传递SynchronousQueue等。

  13. threadFactory:线程工厂,用于创建新线程,可以自定义线程名、优先级等属性。

  14. handler:拒绝策略处理器,当线程池无法接受新任务时采取的策略,如AbortPolicy(抛出异常)、CallerRunsPolicy(调用者自己执行任务)等。

  15. 系统无法处理过多请求的策略:通常采用拒绝策略来处理,或者通过监控系统负载动态调整线程池参数。

  16. Java拒绝任务处理自定义实现接口:可以通过实现RejectedExecutionHandler接口来自定义拒绝策略。

  17. ThreadPoolExecutor提供的处理策略:主要有AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy四种。

18-22. 分别描述了上述四种拒绝策略的工作方式,例如AbortPolicy直接抛出异常,CallerRunsPolicy让调用者所在的线程执行任务,DiscardOldestPolicy丢弃最旧的任务以腾出空间,DiscardPolicy直接丢弃新来的任务不执行也不抛出异常。

  1. JDK中执行任务的方法:主要通过execute()方法提交不需要返回值的任务,而submit()方法提交任务后可以获取Future对象来获取结果或取消任务。

  2. execute和submit的区别:execute()用于提交不需要返回值的任务,而submit()可以提交需要返回值的任务,并且返回一个Future对象用于跟踪任务执行结果。

25-28. 重复了之前对各线程池使用场景的描述。

  1. newWorkStealingPool:利用ForkJoinPool框架,适合大量相互独立的任务,能有效利用多核处理器,特别适合于任务数量大于处理器数量的情况。

  2. 线程池关闭:在Java中,可以通过调用shutdown()shutdownNow()方法来关闭线程池。

  3. shutdownNow:尝试停止所有正在执行的任务,并返回等待执行的任务列表。

  4. shutdown:平滑地关闭线程池,不再接受新任务,等待已提交的任务执行完毕。

  5. IO密集型任务线程数选择:一般设置为CPU核心数的两倍或更高,因为IO密集型任务大部分时间在等待IO操作完成。

  6. CPU密集型任务线程数选择:通常设置为CPU核心数+1或核心数,避免过多线程导致上下文切换频繁,降低效率。

35-40. 描述了不同类型的线程池工作队列的特点,如ArrayBlockingQueue是固定大小的阻塞队列,LinkedBlockingQueue可以是无界的,SynchronousQueue没有容量,仅作为任务传递通道等。

  1. Executors的使用java.util.concurrent.Executors类提供了创建不同类型线程池的便捷方法,但使用时需注意其潜在的资源消耗问题。

  2. Executors创建的线程池实现的接口:通常是ExecutorService接口。

43-44. Executors存在的缺陷及为何不推荐使用:默认配置可能导致资源耗尽(如无界队列导致内存溢出),因此推荐手动配置线程池参数,使用ThreadPoolExecutor构造函数自定义线程池。

  1. 如何创建合理的自定义线程池:应考虑任务类型(CPU密集型或IO密集型)、系统环境(CPU核心数)、任务特性(是否需要返回值、是否需要定时执行)等因素,合理设置核心线程数、最大线程数、队列类型及大小、拒绝策略等。

  2. ThreadPoolExecutor构造函数示例

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, // 核心线程数
    maximumPoolSize, // 最大线程数
    keepAliveTime, // 空闲线程存活时间
    TimeUnit.SECONDS, // 时间单位
    new LinkedBlockingQueue<>(capacity), // 工作队列
    threadFactory, // 线程工厂
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
  1. 常用开源类库创建线程池:除了JDK自带的java.util.concurrent包外,一些框架如Spring Framework也提供了线程池的配置和管理功能,使得线程池的创建和管理更加灵活和方便。
有帮助
无帮助
AI 助理回答生成答案可能存在不准确,仅供参考
0 条回答
写回答
取消 提交回答