这是否意味着两个线程不能同时更改底层数据?或者它是否意味着当多个线程执行给定的代码段时,该代码段将以可预测的结果运行?


当前回答

从本质上讲,在多线程环境中,许多事情都可能出错(指令重新排序,部分构造的对象,由于CPU级别的缓存,相同的变量在不同的线程中具有不同的值等)。

我喜欢Java并发实践中给出的定义:

如果一个[部分代码]在从多个线程访问时行为正确,那么它就是线程安全的,而不考虑运行时环境对这些线程的调度或交错执行,并且在调用代码方面没有额外的同步或其他协调。

正确的意思是程序的行为符合它的规范。

的例子

假设您实现了一个计数器。你可以说它的行为是正确的,如果:

Counter.next()从不返回之前已经返回过的值(为了简单起见,我们假设没有溢出等) 从0到当前值的所有值都已在某个阶段返回(没有跳过任何值)

线程安全计数器将根据这些规则进行操作,而不管并发有多少线程访问它(通常不是简单实现的情况)。

注意:交叉贴在程序员上

其他回答

不要将线程安全性与决定论混淆。线程安全代码也可以是非确定性的。考虑到使用线程代码调试问题的难度,这可能是正常的情况。: -)

线程安全只是确保当一个线程修改或读取共享数据时,没有其他线程可以以改变数据的方式访问它。如果代码依赖于特定的执行顺序来确保正确性,那么除了线程安全所需的同步机制之外,还需要其他同步机制来确保这一点。

线程安全代码是指即使有多个线程同时执行也能正常工作的代码。

http://mindprod.com/jgloss/threadsafe.html

完成其他回答:

只有当方法中的代码做以下两件事之一时,同步才会令人担忧:

使用一些非线程安全的外部资源。 读取或更改持久对象或类字段

这意味着在方法中定义的变量总是线程安全的。对方法的每次调用都有自己版本的这些变量。如果方法是由另一个线程调用的,或者是由同一线程调用的,甚至是方法调用自身(递归),这些变量的值是不共享的。

线程调度不保证是循环的。一个任务可能会以牺牲相同优先级的线程为代价完全占用CPU。你可以使用Thread.yield()来获得良心。你可以使用(java) thread . setpriority (thread . norm_priority -1)来降低线程的优先级

另外还要注意:

迭代这些“线程安全”结构的应用程序的巨大运行时成本(已经被其他人提到)。 Thread.sleep(5000)应该休眠5秒。但是,如果有人更改了系统时间,您可能会睡很长时间或根本没有时间。操作系统记录唤醒时间是绝对的,而不是相对的。

线程安全代码按照指定的方式工作,即使由不同的线程同时输入。这通常意味着,应该不间断地运行的内部数据结构或操作受到保护,不会同时进行不同的修改。

让我们举个例子来回答这个问题:

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。

所以这段代码不是线程安全的。

从本质上讲,所有多线程问题都是由这类问题的某些变体引起的。

解决方案是确保加法和比较操作不能分开(例如,用某种同步代码包围这两个语句),或者设计一个不需要两个操作的解决方案。这样的代码是线程安全的。