什么是线程安全性

给“线程安全性”下个定义相当棘手。很多正式的定义都显得过于复杂,并没有给出实用的指导或者精到的见解:而其他非正式的描述看上去又完全是在兜圈子。在Google上搜索了一下,査到很多定义略举一二:

 

  • 可以被多个程序线程调用,这些线程之间没有非预期的互交。
  • 可以同时被多个线程调用,而调用者不需要任何动作(来确保线程的安全性)。

给出这样的定义,让我们对线程安全性产生困惑是不足为奇的!它们听上去令人怀疑: “如果一个类可以安全地被多个线程使用,它就是线程安全的。”你无法对此论述提出任何争议,但也无法从中得到更多有意义的帮助。我们如何辨别线程安全与非线程安全的类?我们甚至又该如何理解“安全”呢?

任何一个合理的“线程安全性”定义,其关键在于“正确性”的概念。如果我们关于线程安全性的定义是模糊的,那是因为缺少一个明确的“正确性”定义。正确性意味着一个类与它的规约保持一致。良好的规约定义了用于强制对象状态的不变约束以及描述操作影响的后验条件。通常我们不会为类写足够的规约,那么我们还能够知道程序的正确与否么?不能,但是只要我们相信“代码是可以工作的”,就不会阻止我们使用这些类。这种“代码自信”与我们所要实现的正确性紧密相关,所以不妨假设单线程化的正确性是“所见即所知”的事物。乐观地将“正确性”定义为“可被认知事物”后,我们现在可以少兜些圈子来定义“线程安全性” 了:

一个类是线程安全的,是指在被多个线程访问时,类可以持续进行正确的行为。

当多个线程访问一个类时,这个类的行为仍然是正确的,那么称这个类时线程安全的。

注:如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步。

任何单线程化的程序同时也是合法的多线程化的程序,倘若程序在单线程化的环境尚且不正确,那么该程序必然不是线程安全的。对于一个正确实现的对象,顺序性的操作,比如调用公共的方法,读写公共域,不会破坏任何一个不变约束以及后验条件。对于线程安全类的实例进行顺序或并发的一系列搡作,都不会导致实例处于无效状态。

线程安全的类封装了任何必要的同步,因此客户不需要自己提供。
 

示例:一个无状态的servlet

展示了一个简单的因数分解的servlet,从request中解包数据,然后进行因数分解,最后将数据封装到response中。

@ThreadSafe
public class StatelessFactorizer implements Servlet {
    public void service(ServletRequest req, ServletResponse res) {
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = factor(i);
        encodeIntoResponse(res, factors);
    }
}

 

 

StatelessFactorizer像大多数Servlet—样,是无状态的:它不包含域也没有引用其他类的域。一次特定计算的瞬时状态,会唯一地存在本地变最中,这些本地变量存储在线程的栈中,只有执行线程才能访问。一个访问StatelessFactorizer的线程,不会影响访问同一个Servlect的其他线程的计算结果:因为两个线程不共亨状态,它们如同在访问不同的实例。因为线程访问无状态对象的行为,不会影响其他线程访问该对象时的正确性,所以无状态对象是线程安全的。

无状态对象永远是线程安全的

 

多数 Servlet都可以实现为无状态的,这一事实极大地降低了确保Servlet线程安全的负担,只有当Servlet要为不同的请求记录一些信息时,才会将线程安全的需求提到曰程上来。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值