java并发编程实战读书笔记--第六章

任务执行

6.1:在线程中执行任务

1、串行执行任务:一般采用while循环执行,如果执行过程中遇到了I/O等操作阻塞,会造成服务器看似失去了相应,用户体验贼差,不推荐。
2、显示的创建线程:例如HTTP请求任务,每有一个连接请求就创建一个线程,用于处理连接请求。这种办法在一定范围内能提高服务器的响应性和吞吐率,但一旦超出了这个范围,再创建更多的线程只会降低程序的执行速度。
3、创建大量线程的弊端:

  • 线程生命周期的开销非常高
  • 资源消耗非常大
  • 稳定性欠缺

6.2Executor框架

Executor基于生产者–消费者模式,提交任务->生产者; 执行任务->消费者
Executor可以将请求处理任务的提交和任务的实际执行解耦出来

6.2.3:线程池

1、线程池与工作队列息息相关

  • 工作队列保存了所有等待执行的任务
  • 工作者线程从工作队列中获取一个任务执行,然后返回线程池等待下一个任务

2、使用线程池,而不是为每个任务分配一个线程的好处

  • 处理多个请求时分摊了在创建线程和销毁线程过程产生的巨大开销
  • 工作线程一直存在,因此不会因为等待创建线程而延迟任务的执行,提高响应性
  • 防止过多线程相互竞争资源而使应用程序耗尽内存或失败
    3、六种线程池
  • newFixedThreadPool:创建一个固定长度的线程池,每提交一个任务就创建一个线程,知道达到线程池的最大数量。当有线程Exception结束时,线程池会补充一个新的线程。
  • newCachedThreadPool:创建一个可缓存的线程池,如果线程池当前的规模超出了处理请求时,那么会回收空闲的线程,需求增加时,添加新的线程。线程池的规模不存在限制。
  • newSingleThreadPool:单线程的Executor,保证任务的顺序执行。
  • newScheduledThreadPool:创建一个固定长度的线程池,以延迟或定时的任务执行任务。
  • newWorkStealingPool:守护线程,每个线程都维护自己的任务队列,当自己的任务队列执行完了,会去别的线程的任务队列“偷”任务来执行。底层是ForkJoinPool
  • ForkJoinPool:将大任务切分为小任务并行执行,执行完的结果进行合并。

6.2.4:Executor的生命周期

1、JVM只有在所有(非守护)线程全部终止后才会退出,因此若无法正确关闭Executor,那么JVM无法关闭
2、Executor采用异步方式来执行任务
3、为了解决执行服务的生命周期问题,Executor扩展了ExecutorService接口

public interface ExecutorService extends Executor{
	void shutdown();//平稳的关闭,不再接收新的任务、同时等待已经提交的任务执行
	List<Runnable> shutdownNow();//执行暴力的关闭,尝试取消所有运行的任务,并且不再启动队列中尚未启动的任务
	boolean isShutDown();//如果此执行程序已关闭,则返回 true
	boolean isTerminated();//查询ExecutorService是否已经终止
	boolean awaitTermination(long timeout, TimeUint unit) throws InterruptedException;
	//通常调用awaitTermination后会立即调用shutdown,产生同步关闭ExecutorServicce
	Future<?> submit(Runnable task);
	//提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。该 Future 的 get 方法在成功 完成时将会返回 null。 抛出RejectedExecutionException - 如果任务无法安排执行 ,NullPointerException - 如果该任务为 null
}


4、ExecutorService的三种生命周期状态:

  • 运行:初始创建时处于运行状态。
  • 关闭:shutdown方法执行平缓的关闭过程:不接受新任务,等待正在执行的任务完成。shutdownNow方法暴力关闭,直接取消所有运行中的任务。
  • 终止:所有任务完成后,进入终止状态。

6.2.5:延迟任务与周期任务

1、线程池可以提供多个线程来执行延迟任务和周期任务
2、ScheduledThreadPool可以解决Timer解决不了的问题
3、构建自己调度服务时,可以使用DelayQueue

6.3找出可利用的并发性

6.3.2携带结果的任务Callable与Future

1、Runnable与Callable最大的区别:Callable有返回值

//     Callable接口
public interface Callable<V> {
       V call() throws Exception;//Callable有返回值
}

2、Executor执行任务的四个生命周期

  • 创建
  • 提交
  • 开始
  • 完成

3、想取消Executor提交的任务时

  • 任务已提交但尚未开始:可以取消
  • 任务已开始执行:只有当他们能响应中断时,才能取消

4、Future表示一个任务的生命周期

//     Future接口
public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException,
                    CancellationException;
    V get(long timeout, TimeUnit unit)
         throws InterruptedException, ExecutionException,
                CancellationException, TimeoutException;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值