标签:
在线程安全的定义中,最核心的概念就是正确性。如果对线程安全性的定义是模糊的。那就是因为缺乏对正确性的清晰定义。
正确性的含义是,某个类的行为与其规范完全一致。在良好的规范中通常会定义各种不变性条件来约束对象的状态,以及定义各种后验条件来描述对象操作的结果。
其中每个框架都能创建多个线程并在这些线程中调用你编写的代码,因此你需要保证编写的代码是线程安全的。通常,线程安全性的需求并非来源于对线程的直接使用,而是使用像Servlet这样的框架。我们来看一个简单的实例
@ThreadSafe public class StatelessFactorizer extends GenericServlet implements Servlet { public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); BigInteger[] factors = factor(i); encodeIntoResponse(resp, factors); } void encodeIntoResponse(ServletResponse resp, BigInteger[] factors) { } BigInteger extractFromRequest(ServletRequest req) { return new BigInteger("7"); } BigInteger[] factor(BigInteger i) { // Doesn‘t really factor return new BigInteger[] { i }; } }
上述代码当中不包含任何的域,也不包括任何对其它类中域的引用。它不存在任何状态,所以上述代码是绝对的线程安全的。
当我们在无状态的对象中增加一个状态,加入一个类似计数器的东西
@NotThreadSafe public class UnsafeCountingFactorizer extends GenericServlet implements Servlet { private long count = 0; public long getCount() { return count; } public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); BigInteger[] factors = factor(i); ++count; encodeIntoResponse(resp, factors); } void encodeIntoResponse(ServletResponse res, BigInteger[] factors) { } BigInteger extractFromRequest(ServletRequest req) { return new BigInteger("7"); } BigInteger[] factor(BigInteger i) { // Doesn‘t really factor return new BigInteger[] { i }; } }
上述代码则不是线程安全的,因为count变量看似一句简单的代码,但是包括了三个步骤 "读count-修改count-写入count",在这个过程中其结果的状态依赖于之前的状态。
如果计数器一开始都为9,那在某个情况下两个线程读到的值都为9,接着执行递增操作,并且都将计数器的值设为10。那么有一次递增操作就丢失了。
所以上述代码则不是线程安全的。
在并发编程中,这种由于不恰当的执行时序而出现不正确的结果是一种非常重要的情况,它有一个正式的名字:竞态条件。
标签:
原文地址:http://www.cnblogs.com/chenjianxiang/p/5777714.html