Java并发编程实战读书笔记(三)

任务执行

无限制创建线程的不足

在讨论并发编程和多线程处理的场景中,“为每个任务分配一个线程”这种策略存在一系列的不足,特别是在生产环境中需要创建大量线程时。以下是这种策略的主要问题:

  1. 线程生命周期的开销:线程的创建和销毁过程需要时间和系统资源。这会导致处理请求的延迟,并增加JVM和操作系统的负担。对于需要处理大量轻量级请求的应用(如大多数服务器应用),为每个请求创建一个新线程会消耗大量计算资源。

  2. 资源消耗:活跃的线程消耗系统资源,尤其是内存。如果可运行的线程数量超过可用处理器的数量,一些线程将处于闲置状态。这些大量的空闲线程不仅占用内存,还增加了垃圾回收器的负担,并在竞争CPU资源时产生额外性能开销。如果已有足够多的线程使所有CPU保持忙碌,再创建更多线程实际上会降低性能。

  3. 稳定性问题:可创建线程的数量有限制,这个限制因平台不同而异,受多种因素影响,包括JVM启动参数、Thread构造函数中的栈大小请求以及底层操作系统对线程的限制等。超出这些限制可能导致抛出OutOfMemoryError异常,从这种错误中恢复非常危险,更可行的方法是设计程序以避免超出限制。

  4. 系统吞吐率和性能:在一定的范围内,增加线程可以提高系统吞吐率,但超出这个范围后,继续创建线程只会降低程序执行速度。过多地创建线程可能导致应用程序崩溃。

  5. 高负载下的风险:在应用程序部署后并处于高负载下运行时,无限制地创建线程会导致问题暴露,恶意用户或过多用户可能使Web服务器负载达到阈值并崩溃。对于需要高可用性并能在高负载情况下平稳降低性能的服务器而言,这将是一个严重的故障。

Executor框架

Executor基于生产者-消费者模式,其中提交任务的操作相当于生产者(生成待完成的工作单元),执行任务的线程则相当于消费者(执行这些工作单元)。在程序中实现生产者-消费者设计时,使用Executor是最简单的方式。

使用线程池执行任务相比为每个任务分配一个线程有更多的优势。线程池通过重用现有线程而不是创建新线程,减少了线程创建和销毁的开销。此外,由于工作线程通常已经存在,任务的执行不会因等待线程创建而延迟,这提高了响应性。适当调整线程池大小可以确保有足够的线程使处理器保持忙碌,同时防止过多线程竞争资源导致应用程序耗尽内存或失败。

Java类库提供了灵活的线程池和一些有用的默认配置。可以通过调用Executors中的静态工厂方法来创建线程池:

  • newFixedThreadPool:创建一个固定长度的线程池,达到最大数量后不再变化,如果线程因异常结束,会补充新线程。
  • newCachedThreadPool:创建一个可缓存的线程池,根据需求增加或回收空闲线程,线程池规模无限制。
  • newSingleThreadExecutor:创建单个工作线程的Executor,按任务队列顺序串行执行,如FIFO、LIFO、优先级。
  • newScheduledThreadPool:创建一个固定长度的线程池,以延迟或定时方式执行任务,类似于Timer。

newFixedThreadPoolnewCachedThreadPool返回ThreadPoolExecutor实例,可以直接用来构造专门用途的executor。第8章将深入讨论线程池的配置选项。

TaskExecutionWebServer中的Web服务器使用了一个带有有界线程池的Executor。通过execute方法将任务提交到工作队列中,工作线程反复地从队列中取出任务并执行它们。

好的,以下是为您整理后的内容:
为了解决执行服务的生命周期问题,Executor扩展了ExecutorService接口,添加了一些用于生命周期管理的方法,以及一些便于任务提交的方法。ExecutorService的生命周期有三种状态:运行、关闭和已终止。初始创建时处于运行状态。

  • void shutdown();:启动平缓的关闭过程,不再接受新任务,等待已提交的任务完成。
  • List<Runnable> shutdownNow();:尝试粗暴关闭,取消所有正在执行的任务,不启动尚未开始的任务。
  • boolean isShutdown();:检查是否开始关闭过程。
  • boolean isTerminated();:检查所有任务是否完成,ExecutorService是否处于终止状态。
  • boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;:等待直到所有任务完成或超时,或当前线程被中断,之后返回true;如果已经进入终止状态,立刻返回true。

ExecutorService关闭后提交的任务将由“拒绝执行处理器”处理,它会抛弃任务或使execute方法抛出RejectedExecutionException。通常在调用awaitTermination后会立即调用shutdown以同步关闭ExecutorService

Timer类用于管理延迟任务(如“100ms后执行该任务”)和周期任务(如“每10ms执行一次该任务”)。但由于Timer存在一些缺陷,建议使用ScheduledThreadPoolExecutor来代替。ScheduledThreadPoo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

庄隐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值