2.5 活跃性与性能
在UnsafeCachingFactorizer中,我们通过在因数分解Servlet中引入了缓存机制来提升性能。在缓存中需要使用共享状态,因此需要通过同步来维护状态的完整性。然而,如果使用SynchronizedFactorizer中的同步方式,那么代码的执行性能将非常糟糕。SynchronizedFactorizer中采用的同步策略是,通过Servlet对象的内置锁来保护每一个状态变量,该策略的实现方式也就是对整个service方法进行同步。虽然这种简单且粗粒度的方法能确保线程安全性,但付出的代价却很高。
由于service是一个synchronized方法,因此每次只有一个线程可以执行。这就背离了Serlvet框架的初衷,即Serlvet需要能同时处理多个请求,这在负载过高的情况下将给用户带来糟糕的体验。如果Servlet在对某个大数值进行因数分解时需要很长的执行时间,那么其他的客户端必须一直等待,直到Servlet处理完当前的请求,才能开始另一个新的因数分解运算。如果在系统中有多个CPU系统,那么当负载很高时,仍然会有处理器处于空闲状态。即使一些执行时间很短的请求,比如访问缓存的值,仍然需要很长时间,因为这些请求都必须等待前一个请求执行完成。
图2-1给出了当多个请求同时到达因数分解Servlet时发生的情况:这些请求将排队等待处理。我们将这种Web应用程序称之为不良并发(Poor Concurrency)应用程序:可同时调用的数量,不仅受到可用处理资源的限制,还受到应用程序本身结构的限制。幸运的是,通过缩小同步代码块的作用范围,我们很容易做到既确保Servlet的并发性,同时又维护线程安全性。要确保同步代码块不要过小,并且不要将本应是原子的操作拆分到多个同步代码块中。应该尽量将不影响共享状态且执行时间较长的操作从同步代码块中分离出去,从而在这些操作的执行过程中,其他线程可以访问共享状态。 ...
Get Java并发编程实战 now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.