这是否意味着两个线程不能同时更改底层数据?或者它是否意味着当多个线程执行给定的代码段时,该代码段将以可预测的结果运行?
当前回答
是的,是的。它意味着数据不会被多个线程同时修改。然而,您的程序可能会像预期的那样工作,并且看起来是线程安全的,即使它根本不是。
请注意,结果的不可预测性是“竞态条件”的结果,它可能导致数据以与预期顺序不同的顺序被修改。
其他回答
用最简单的话来说:P 如果在一个代码块上执行多个线程是安全的,那么它就是线程安全的*
*适用条件
条件被其他的答案提到,比如 1. 如果你执行一个线程或多个线程,结果应该是相同的。
不要将线程安全性与决定论混淆。线程安全代码也可以是非确定性的。考虑到使用线程代码调试问题的难度,这可能是正常的情况。: -)
线程安全只是确保当一个线程修改或读取共享数据时,没有其他线程可以以改变数据的方式访问它。如果代码依赖于特定的执行顺序来确保正确性,那么除了线程安全所需的同步机制之外,还需要其他同步机制来确保这一点。
我想在其他好的答案之上添加一些更多的信息。
线程安全意味着多个线程可以在同一个对象中读写数据,而不会出现内存不一致错误。在高度多线程的程序中,线程安全的程序不会对共享数据造成副作用。
看看这个SE问题,了解更多细节:
线程安全是什么意思?
线程安全程序保证内存一致性。
从oracle文档页高级并发API:
内存一致性属性:
Java™语言规范的第17章定义了内存操作(如共享变量的读写)的happens-before关系。只有当写操作发生时(在读操作之前),一个线程的写操作的结果才保证对另一个线程的读操作可见。
synchronized和volatile结构,以及Thread.start()和Thread.join()方法,可以形成happens-before关系。
concurrent中所有类的方法及其子包将这些保证扩展到更高级别的同步。特别是:
Actions in a thread prior to placing an object into any concurrent collection happen-before actions subsequent to the access or removal of that element from the collection in another thread. Actions in a thread prior to the submission of a Runnable to an Executor happen-before its execution begins. Similarly for Callables submitted to an ExecutorService. Actions taken by the asynchronous computation represented by a Future happen-before actions subsequent to the retrieval of the result via Future.get() in another thread. Actions prior to "releasing" synchronizer methods such as Lock.unlock, Semaphore.release, and CountDownLatch.countDown happen-before actions subsequent to a successful "acquiring" method such as Lock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await on the same synchronizer object in another thread. For each pair of threads that successfully exchange objects via an Exchanger, actions prior to the exchange() in each thread happen-before those subsequent to the corresponding exchange() in another thread. Actions prior to calling CyclicBarrier.await and Phaser.awaitAdvance (as well as its variants) happen-before actions performed by the barrier action, and actions performed by the barrier action happen-before actions subsequent to a successful return from the corresponding await in other threads.
与其认为代码或类是线程安全的,我认为将操作视为线程安全的更有帮助。如果两个操作在从任意线程上下文运行时按照指定的方式运行,那么它们就是线程安全的。在许多情况下,类将以线程安全的方式支持一些操作组合,而其他则不支持。
例如,许多像数组列表和散列集这样的集合可以保证,如果它们最初只由一个线程访问,并且在引用对任何其他线程可见后永远不会被修改,那么它们可以被任何线程组合以任意方式读取而不受干扰。
More interestingly, some hash-set collections such as the original non-generic one in .NET, may offer a guarantee that as long as no item is ever removed, and provided that only one thread ever writes to them, any thread that tries to read the collection will behave as though accessing a collection where updates might be delayed and occur in arbitrary order, but which will otherwise behave normally. If thread #1 adds X and then Y, and thread #2 looks for and sees Y and then X, it would be possible for thread #2 to see that Y exists but X doesn't; whether or not such behavior is "thread-safe" would depend upon whether thread #2 is prepared to deal with that possibility.
As a final note, some classes--especially blocking communications libraries--may have a "close" or "Dispose" method which is thread-safe with respect to all other methods, but no other methods that are thread-safe with respect to each other. If a thread performs a blocking read request and a user of the program clicks "cancel", there would be no way for a close request to be issued by the thread that's attempting to perform the read. The close/dispose request, however, may asynchronously set a flag which will cause the read request to be canceled as soon as possible. Once close is performed on any thread, the object would become useless, and all attempts at future actions would fail immediately, but being able to asynchronously terminate any attempted I/O operations is better than require that the close request be synchronized with the read (since if the read blocks forever, the synchronization request would be likewise blocked).
从本质上讲,在多线程环境中,许多事情都可能出错(指令重新排序,部分构造的对象,由于CPU级别的缓存,相同的变量在不同的线程中具有不同的值等)。
我喜欢Java并发实践中给出的定义:
如果一个[部分代码]在从多个线程访问时行为正确,那么它就是线程安全的,而不考虑运行时环境对这些线程的调度或交错执行,并且在调用代码方面没有额外的同步或其他协调。
正确的意思是程序的行为符合它的规范。
的例子
假设您实现了一个计数器。你可以说它的行为是正确的,如果:
Counter.next()从不返回之前已经返回过的值(为了简单起见,我们假设没有溢出等) 从0到当前值的所有值都已在某个阶段返回(没有跳过任何值)
线程安全计数器将根据这些规则进行操作,而不管并发有多少线程访问它(通常不是简单实现的情况)。
注意:交叉贴在程序员上