CompletableFutures 线程安全吗?

Bri*_*ian 3 java multithreading completable-future spring-async

我有一个调用两个单独线程的线程。CompletableFuture它向这两个子线程传递相同的内容。如果.get()同时在这两个线程中调用,我会遇到任何类型的并发问题吗?

\n
    \n
  • 它会腐蚀吗CompletableFuture
  • \n
  • 我是否有可能看不到对返回的对象所做的最后更改.get()
  • \n
  • 如果我之后修改该对象怎么办?
  • \n
\n

作为一个具体的例子,在下面的代码中,假设完成cfInput.get()后返回的对象没有发生任何变化,两个线程是否有可能打印不同的值?cfInput

\n
public void mainClass(CompletableFuture<ObjA> cfInput){\n  class1.doAsync1(cfInput);\n  class2.doAsync2(cfInput);\n}\n\n@Async\npublic void doAsync1(CompletableFuture<ObjA> cfInput){\n  //logic\n  System.out.println(cfInput.get().getObjB().getBlah());\n  //logic\n}\n\n@Async\npublic void doAsync2(CompletableFuture<ObjA> cfInput){\n  //logic\n  System.out.println(cfInput.get().getObjB().getBlah());\n  //logic\n}\n\npublic class ObjA{\n  private ObjB objB;\n  public ObjB getObjB();\n  public void setObjB();\n}\npublic class ObjB{\n  private String blah;\n  public String getBlah();\n  public void setBlah();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Did*_*r L 5

CompletableFuture本质上是线程安全的

\n

您可以简单地假设这一点,因为此类被设计为在多线程上下文中使用,但是在的描述java.util.concurrent中更清楚地指定了这一点:

\n
\n

内存一致性属性

\n

Java 语言规范第 17 章定义了内存操作(例如共享变量的读写)的happens-before关系。仅当写入操作发生在读取操作之前时,才保证一个线程的写入结果对另一个线程的读取可见。\n[\xe2\x80\xa6]\njava.util.concurrent中及其中所有类的方法子包将这些保证扩展到更高级别的同步。尤其:

\n
    \n
  • [\xe2\x80\xa6]
  • \n
  • 在通过另一个线程检索结果之后,由 Future 表示的异步计算所采取的操作发生在操作之前。Future.get()
  • \n
\n
\n

因此,这意味着线程在完成 future 之前执行的任何写入对于调用该 future 的任何其他线程都是可见的get()(即它 \xe2\x80\x9c发生在\xe2\x80\x9d 之前)。

\n

您的对象本质上不是线程安全的

\n

\xe2\x80\xa6 也不受 \xe2\x80\x9c 保护\xe2\x80\x9dCompletableFuture

\n

尽管CompletableFuture它本身是线程安全的,并且为写入的可见性提供了一些保证,但它并不能使您的对象成为线程安全的。

\n

例如,如果您修改 返回的对象,则在您进入另一个发生之前CompletableFuture.get()关系之前,不保证这些更改对任何其他线程都可见。因此,您可能需要额外的同步来强制该对象的线程安全。

\n