这是否意味着两个线程不能同时更改底层数据?或者它是否意味着当多个线程执行给定的代码段时,该代码段将以可预测的结果运行?
当前回答
让我们举个例子来回答这个问题:
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。
所以这段代码不是线程安全的。
从本质上讲,所有多线程问题都是由这类问题的某些变体引起的。
解决方案是确保加法和比较操作不能分开(例如,用某种同步代码包围这两个语句),或者设计一个不需要两个操作的解决方案。这样的代码是线程安全的。
其他回答
是也不是。
线程安全不仅仅是确保共享数据一次只能被一个线程访问。您必须确保对共享数据的顺序访问,同时避免竞争条件、死锁、活动锁和资源短缺。
当多个线程同时运行时,不可预知的结果并不是线程安全代码的必要条件,但这通常是一种副产品。例如,您可以使用一个共享队列、一个生产者线程和几个消费者线程来设置生产者-消费者方案,并且数据流可能完全可预测。如果你开始引入更多的消费者,你会看到更多随机的结果。
线程安全代码是指即使有多个线程同时执行也能正常工作的代码。
http://mindprod.com/jgloss/threadsafe.html
我喜欢Brian Goetz的Java并发实践中的定义,因为它的全面性
如果一个类在从多个线程访问时行为正确,那么它就是线程安全的,而不管运行时环境对这些线程的执行是如何调度或交错的,并且在调用代码方面没有额外的同步或其他协调。
不要将线程安全性与决定论混淆。线程安全代码也可以是非确定性的。考虑到使用线程代码调试问题的难度,这可能是正常的情况。: -)
线程安全只是确保当一个线程修改或读取共享数据时,没有其他线程可以以改变数据的方式访问它。如果代码依赖于特定的执行顺序来确保正确性,那么除了线程安全所需的同步机制之外,还需要其他同步机制来确保这一点。
让我们举个例子来回答这个问题:
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。
所以这段代码不是线程安全的。
从本质上讲,所有多线程问题都是由这类问题的某些变体引起的。
解决方案是确保加法和比较操作不能分开(例如,用某种同步代码包围这两个语句),或者设计一个不需要两个操作的解决方案。这样的代码是线程安全的。