简书 賈小強
转载请注明原创出处,谢谢!
线程安全的定义常常让人迷惑,搜索引擎会发现无数定义,比如:
- 多个线程同时执行也能正确工作就是线程安全的代码
- 多个线程同时执行能以正确的方式操纵共享数据就是线程安全的代码。
而且还有很多类似的定义
你是否认为这种定义实际上没有任何意义而且还让人更加迷惑?虽然这些定义没错,但事实是他们没有提供任何实际的帮助或观点。我们如何区分线程安全类和不安全类?我们所谓的“安全”是什么意思?
线程安全的正确性是什么?
线程安全的任何合理定义的核心是正确性的概念。因此,在了解线程安全之前,我们首先应该理解这个“正确”。
正确性意味着一个类符合它的规范。
一个好的类规范将在任何给定的时间拥有关于一个类的状态的所有信息,在其上执行某些操作以及它的后置条件。但我们经常没有为我们的类写出足够的规范,我们怎么可能知道它们能正确的使用呢?我们不能,但这并不能阻止我们使用它们,一旦我们说服自己“代码有效”。这种“代码自信”来自于我们接近正确。
乐观地将“正确性”定义为可以被识别的东西,现在我们可以用一种不那么绕的方式定义线程安全:当一个类在从多个线程访问时继续正常运行时,它是线程安全的。
不管运行时环境线程调度如何交织,只有当从多个线程访问它行为正确,以及调用代码的部分没有额外的同步或其他协调,那么这个类是线程安全的
如果这个宽泛的“正确性”让你觉得比较烦,那么您可能会认为线程安全类是一个在并发环境中比单线程环境中更糟的类。线程安全类封装了所需的同步,这样客户端就不必提供自己的同步。
示例:无状态servlet
线程安全类的一个很好的例子是java servlet没有字段(fields)和引用(references),没有来自别的类的字段,它们是无状态的。
public class StatelessFactorizer implements Servlet
{
public void service(ServletRequest req, ServletResponse resp)
{
BigInteger i = extractFromRequest(req);
BigInteger[] factors = factor(i);
encodeIntoResponse(resp, factors);
}
}
在特定计算瞬间数据仅存储在正在在执行线程的堆栈上,即局部变量。一个线程访问一个statelessfactorizer不会影响另一个线程访问同一个statelessfactorizer产生的结果;因为两个线程不共享状态,就好像他们访问不同的实例。由于某个线程对无状态对象的的访问操作不会影响其他线程中操作的正确性,无状态对象是线程安全的。
这就是围绕线程安全的这个小而重要的概念
Happy Learning !!