daicy
发布于 2020-04-14 / 1265 阅读
0
0

Java并发性–线程安全性?

定义线程安全性出奇的棘手。快速的Google搜索会发现许多类似的“定义”:

线程安全代码是即使许多线程同时执行也可以运行的代码。
如果一段代码仅以保证多个线程同时安全执行的方式操作共享数据结构,则它是线程安全的。
并且还有更多类似的定义。

您是否不认为上述定义实际上并没有传达任何有意义的信息,甚至会增加一些混乱。尽管不能排除那样的定义,因为它们没有错。但是事实是它们没有提供任何实际帮助或观点。我们如何区分线程安全的类和不安全的类?我们什至“安全”是什么意思?

什么是线程安全的正确性?

线程安全性的任何合理定义的核心是正确性的概念。因此,在了解线程安全性之前,我们应该首先了解“ correctness”。

正确性表示一个类符合其规范。

您将同意,良好的类规范将在任何给定时间具有有关类状态的所有信息,并且如果对它执行了某些操作,则它是后置条件。由于我们经常没有为类编写足够的规范,我们怎么可能知道它们是正确的?我们不能,但是一旦我们说服自己“ 代码可以工作 ” ,那也不会阻止我们继续使用它们。这种“代码置信度 ”与我们许多人接近正确性的程度差不多。

乐观地将“正确性”定义为可以识别的事物之后,我们现在可以以一种不太循环的方式定义线程安全性:当一个类在从多个线程访问时继续正确运行时,它是线程安全的。

如果一个类在从多个线程访问时能正确运行,则无论它在运行时环境中对那些线程的执行进行调度或交织,并且在调用代码部分没有任何其他同步或其他协调的情况下,如果它行为正确,则该线程是安全的。

如果此处对“正确性”的宽松使用使您感到困扰,则您可能更愿意将线程安全类认为是在并发环境中比在单线程环境中不会损坏的类。线程安全类封装了任何需要的同步,因此客户端不需要提供自己的同步。

示例:无状态Servlet

线程安全类的一个很好的例子是Java Servlet,它没有字段和引用,也没有其他类的字段等。它们是无状态的。

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

特定计算的瞬态仅存在于局部变量中,这些局部变量存储在线程的堆栈中,并且只有执行线程才能访问。一个线程访问a StatelessFactorizer不会影响另一个线程访问a 的结果StatelessFactorizer;因为两个线程不共享状态,所以好像它们正在访问不同的实例。由于线程访问无状态对象的动作不会影响其他线程中操作的正确性,因此无状态对象是线程安全的。

这就是关于什么是线程安全的小而重要的概念的全部内容?

学习愉快!


评论