线程安全:类的实例

For*_*hit 1 java multithreading

下面是第一个代码片段 Java concurrency in Pratice。我不明白这个类为什么不是线程安全的?是不是每次线程需要调用 getNext() 方法时,它都会先创建这个类的实例?两个线程可以共享该类的同一个实例吗(barring explicit share)?

@NotThreadSafe
public class UnsafeSequence {
private int value;
/** Returns a unique value. */
public int getNext() {
return value++;
}
 }
Run Code Online (Sandbox Code Playgroud)

小智 5

我不明白这个类为什么不是线程安全的?

您现在可能已经有了答案,但为了完整起见,我将其包含在此处。)

问题在于value++声明。这是一个由多部分组成的声明。

  1. 的值value被读取。
  2. 读取的值加一。
  3. 新值存储在 中value

该序列可以由另一个线程混合。说value5。如果两个线程调用getNext()(在同一个实例上),您会期望value它们7完成时。但是,如果两个线程在任何线程执行步骤 3 之前都完成了步骤 1 和 2,则它们都会将值6写入value

  • 线程 1 执行步骤 1 - 读取5
  • 线程 2 执行步骤 1 - 读取5
  • 线程 2 执行步骤 2 -5增加1
  • 线程 2 执行步骤 3 - 保存值6
  • 线程 1 执行步骤 2 -5递增1
  • 线程 1 执行步骤 3 - 保存值6

是不是每次线程需要调用 getNext() 方法时,它都会先创建这个类的实例?

不是每次。那会new UnsafeSequence().getNext()一遍又一遍地重复,这是没有意义的。但也许这并不完全是你的意思。每个线程都可以有自己的类实例并调用getNext()它。这种情况下就没有问题了。

两个线程可以共享此类的同一个实例(除非显式共享)?

不,必须以某种方式共享实例。但它可能会在你不知情的情况下被分享。例如,某些类可能有static一个返回 的实例的方法UnsafeSequence。您不知道每次返回的实例是否相同,或者每次调用是否创建一个新实例。除非这在某处有记录。


API 文档中关于类是否线程安全的讨论是指在线程之间共享实例的情况。如果某个实例不共享,则可以在多线程应用程序中使用它,只要它可用并仅由其中一个线程使用即可。