这是否意味着两个线程不能同时更改底层数据?或者它是否意味着当多个线程执行给定的代码段时,该代码段将以可预测的结果运行?
当前回答
是的,是的。它意味着数据不会被多个线程同时修改。然而,您的程序可能会像预期的那样工作,并且看起来是线程安全的,即使它根本不是。
请注意,结果的不可预测性是“竞态条件”的结果,它可能导致数据以与预期顺序不同的顺序被修改。
其他回答
是也不是。
线程安全不仅仅是确保共享数据一次只能被一个线程访问。您必须确保对共享数据的顺序访问,同时避免竞争条件、死锁、活动锁和资源短缺。
当多个线程同时运行时,不可预知的结果并不是线程安全代码的必要条件,但这通常是一种副产品。例如,您可以使用一个共享队列、一个生产者线程和几个消费者线程来设置生产者-消费者方案,并且数据流可能完全可预测。如果你开始引入更多的消费者,你会看到更多随机的结果。
让我们举个例子来回答这个问题:
class NonThreadSafe {
private int count = 0;
public boolean countTo10() {
count = count + 1;
return (count == 10);
}
countTo10方法将1加到计数器上,如果计数达到10则返回true。它应该只返回true一次。
只要只有一个线程在运行代码,这就可以工作。如果两个线程同时运行代码,就会出现各种问题。
例如,如果count从9开始,一个线程可以将1加到count(得到10),但随后第二个线程可以进入该方法,在第一个线程有机会执行与10的比较之前再次加1(得到11)。然后两个线程进行比较,发现count是11,并且都不返回true。
所以这段代码不是线程安全的。
从本质上讲,所有多线程问题都是由这类问题的某些变体引起的。
解决方案是确保加法和比较操作不能分开(例如,用某种同步代码包围这两个语句),或者设计一个不需要两个操作的解决方案。这样的代码是线程安全的。
从本质上讲,在多线程环境中,许多事情都可能出错(指令重新排序,部分构造的对象,由于CPU级别的缓存,相同的变量在不同的线程中具有不同的值等)。
我喜欢Java并发实践中给出的定义:
如果一个[部分代码]在从多个线程访问时行为正确,那么它就是线程安全的,而不考虑运行时环境对这些线程的调度或交错执行,并且在调用代码方面没有额外的同步或其他协调。
正确的意思是程序的行为符合它的规范。
的例子
假设您实现了一个计数器。你可以说它的行为是正确的,如果:
Counter.next()从不返回之前已经返回过的值(为了简单起见,我们假设没有溢出等) 从0到当前值的所有值都已在某个阶段返回(没有跳过任何值)
线程安全计数器将根据这些规则进行操作,而不管并发有多少线程访问它(通常不是简单实现的情况)。
注意:交叉贴在程序员上
简单地说,如果许多线程同时执行这段代码,代码将运行良好。
线程安全代码按照指定的方式工作,即使由不同的线程同时输入。这通常意味着,应该不间断地运行的内部数据结构或操作受到保护,不会同时进行不同的修改。
推荐文章
- 在支持循环和函数的语言中,是否存在“goto”的合法用例?
- 跨线程操作无效:控件“textBox1”从创建它的线程以外的线程访问
- 为什么不使用异常作为常规的控制流呢?
- 线和纤维的区别是什么?
- 什么是序列化?
- Java同步方法锁定对象,或方法?
- Haskell对Node.js的响应是什么?
- 每个递归都可以转换成迭代吗?
- 调用线程必须是STA,因为许多UI组件都要求这一点
- Redis是单线程的,那么它如何做并发I/O?
- 什么是ORM,它是如何工作的,我应该如何使用它?
- 我能在服务器端应用程序(PHP、Ruby、Python等)上读取URL的哈希部分吗?
- 多少个参数是太多?
- 对于没有null的语言的最佳解释
- Java:如何测试调用System.exit()的方法?