这段代码不是线程安全的-需要吗?

时间:2019-01-08 17:14:41

标签: java thread-safety

我有一堂课,在很大程度上简化了相关部分,看起来像这样(虚拟名称):

@RequiredArgsConstructor
public class SomeClass {
   private final SomeProvider someProvider;
   private SomeDataStore store = null;

   private SomeDataStore getStoreAttributes() {
      if (store == null) {
          store = new SomeDataStore(someProvider, <other params>)
      }
      return store;
   }
}

一个队友评论说store == null的检查不是线程安全的,因为store的值可能在线程之间改变。但是,我们不确定这是否重要,因为没有任何事情将store设置为null,并且我没有看到多个线程尝试将相同的store设置为new SomeDataStore( ...),因为数据存储区对代码而言是只读的。

我的线程安全性是否缺少任何问题?

谢谢!

3 个答案:

答案 0 :(得分:2)

  

我的线程安全性是否缺少任何问题?

是的。至少这些:

  • 如果您有两个或多个线程共享的SomeClass实例,则这些线程中至少有一个曾经将store成员设置为非null值,并且任何其他线程在该实例上调用getStoreAttributes(),那么您将发生数据竞争。在这种情况下,程序的行为是不确定的。

  • 在诸如此类的数据竞赛中可以观察到的行为中

    • 一个或多个线程从不观察到对store
    • 的更新
    • 不同的线程以似乎不一致的顺序观察到对store的更新
  • 即使您可以假设对store的读取和写入都是原子的,因此没有数据争用,您 still 仍然会遇到两个不同的线程可以两者都观察到storenull并同时输入if块。结果,他们每个人都会实例化一个新的SomeDataStore,该方法将返回该新fieldset,从而破坏了明显的目的。

答案 1 :(得分:1)

在给定的示例中,如果有多个线程在调用方法“ getStoreAttributes()”,则“ store”实例变量可以初始化两次。 如果您认为多次初始化存储变量是可以的,那么就可以了,无需添加任何线程安全性。 如果您不想添加诸如同步块之类的线程安全功能,请至少使“存储”变量易失,这将确保线程将从内存中读取其最新状态。

但是从“存储”这个名字来看,它似乎是一些资源,并且无缘无故地多次初始化似乎并不正确。您可以通过增加线程安全性来节省它。 如果一个线程正在初始化资源,其他线程将等待并使用初始化的资源。 您可以实施双重锁定以确保相同。

答案 2 :(得分:0)

简短的答案是,您应该努力以使其线程安全的方式编写代码。现在,答案很长:据您所知,由于这种不安全的操作,您的代码目前没有问题。假设您是一个神童,并且已对当前情况进行了正确的评估,则通过将其纳入代码库,您已经添加了某种形式的债务,某些代码可能会在将来容易证明有问题,并且可能会导致查找困难错误。很难说,但是我看到您正在尝试创建一个缓存的字段,有一些方法可以使此线程安全。