《JAVA并发编程实践》学习笔记(第六.七章)

2部分

构建并发应用程序

第6章 任务执行

       大多数并发应用程序都是围绕执行任务(task)进行管理。所谓任务就是抽象、离散的工作单元(unit of work)。

6.1 在线程中执行任务

       在围绕任务来管理应用程序时,第一步要指明一个清晰的任务边界(task boundaries)。理想情况下,任务是独立的活动:它的工作并不依赖于其他任务的状态、结果或者边界效应(side effect)。

       在正常的负载下,服务器应用程序应该兼具良好的吞吐量快速的相应性。

       顺序化处理几乎不能为服务器应用程序提供良好的吞吐量或快速的响应性。

6.1.2 显示地为任务创建线程

       为了提供更好的响应性,可以为每个服务请求创建一个新的线程。

       3个主要结论:

1.    执行任务的负载已经脱离了主线程,主循环能够迅速地重新开始等待下一个连接。这使得程序可以在完成前面的请求之前接受新的请求,从而提高响应性。

2.    并行处理任务,这使得多个请求可以同时得到服务。如果有多个处理器,或者处于I/O未完成,锁请求以及资源可用性等任何因素需要阻塞任务时,程序的吞吐哦量会得到提高。

3.    任务处理代码必须是线程安全的,因为有多个任务会并发地调用它。

 

6.1.3 物限制创建线程的缺点

 

6.2 Executor框架

       任务是逻辑上的工作单元,线程是任务异步执行的机制。顺序执行会产生糟糕的响应性和吞吐量,“每任务每线程”会给资源管理带来麻烦。

6.2.3 线程池

       线程池管理一个工作线程的同构池(homogeneous pool),线程池是与工作队列(work queue)紧密绑定的。

     线程池好处

线程池重用存在的线程,而不是创建新的线程,这可以在处理多请求时抵消线程创建、消亡产生的开销。另外一个好处是,在请求到达时,工作者线程通常已经存在,用户创建线程的等待时间并不会延迟任务的执行,因此提高了响应性。通过调整线程池的大小,你可以得到足够多的线程以保持处理器忙碌,同时可以防止过多的线程互相竞争资源,导致应用程序耗尽内存或者失败。

大量互相独立且同类的任务进行并发处理,会将程序的任务量分配到不同的任务中,这样才能真真的获得性能的提升。

    

第7章 取消和关闭

1.1 任务取消

当外部代码能够在活动自然完成前,把它更改为完成状态,那么这个活动被称为可取消的(cancellable)。

       取消一个活动的原因有很多:

1.    用户请求的取消;

2.    现实活动;

3.    应用程序事件;

4.    错误;

5.    关闭;

在Java中,没有哪一种用来停止线程的方式是绝对安全的,因此没有哪一种方式优先用来停止任务。

       一个可取消的任务必须拥有取消资格(cancellation policy),

7.1.1 中断

       特定阻塞库类的方法支持中断,线程中断时一个协作机制,一个线程给另一个线程发送信号量(signal),通知它在方便或者可能的情况下停止正在做的工作,去做其他事情。

       当线程在并不处于阻塞状态的情况下发生中断状态,会设置线程的中断状态,然后一直等到被取消的活动获取中断状态,来检查是否发生了中断。

       调用interrupt并不意味着必然停止目标线程正在运行的工作;它仅仅传递了请求中断的消息。

       对中断最好的理解:它并不会正真的中断一个正在运行的线程;仅仅发出中断请求,线程自己会在下一个方便的时刻中断(这些时刻被称为取消点,cancellation point).

       中断通常是实现取消最明智的选择。

7.1.2 中断策略

       中断策略中最有意义的是对线程级(thread-level)和服务级(service level)取消的规定:尽可能迅速推出,如果需要的话进行清理,可能的话通知其拥有的实体,这个线程已经推出。

       任务不会再自己拥有的线程中执行;他们借用属于服务的线程,比如线程池。

       每一个线程都有自己的中断策略,所以你不应该中断线程,除非你知道中断对这个线程意味着什么。

7.1.3 中断响应

       当调用可用中断的阻塞函数时,有两种处理InterruptedException的实用策略:

1.    传递异常(和可能发生在特定任务的清除时),使你的方法也成为可中断的阻塞方法;

2.    或者保存中断状态,上层调用栈中的代码能够对其进行处理。

只有实现了线程中断策略的代码才可以接受中断请求。通用目的的任务和库的代码绝不应该接收中断请求。

 

7.1.5 通过Future取消

       我们曾经用到过一个抽象体,它可以管理任务的生命周期,异常处理,并有利于取消——Future.

7.1.6 处理不可中断阻塞

       获得锁。如果一个线程在等待内部锁,那么如果不能确保它最终获得锁,并且作出足够多的努力,让你能够以其他方式获得它的注意,你是不能停止它的。

       对于线程持有的服务,只要服务的存在时间大于创建线程的方法存在的时间,那么就应该提供声明周期方法。

       在一个长时间运行的应用程序中,所有的线程都要给未捕获异常设置一个处理器,这个处理器至少要将异常信息记入日志中。

 

7.4 JVM关闭

7.4.1 钩子函数

       关闭钩子函数全部都是并发执行的,关闭日志文件可能引起其他需要使用日志服务的关闭钩子的麻烦。为了避免这个麻烦,关闭钩子不应该依赖于可能被应用程序或其他关闭钩子关闭的服务。

7.4.2 精灵线程

       线程被分为两种:普通线程和精灵线程。JVM启动时创建的所有线程,除了主线程之外,其他都是精灵线程(比如垃圾回收器和其他类似线程)。当一个新的线程创建时,新线程继承了创建它的线程的后台状态,所以默认情况下,任何主线程创建的线程都是普通线程。

       普通线程与精灵线程之间的区别仅仅在于退出时会发生什么。

       应用程序中,精灵线程不能替代对服务的生命周期恰当、良好的管理。

7.4.3 Finalizer

       避免使用Finalizer

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值