Mongodb 带有 mongodb bson 库的驱动程序导致 completableFuture 在单独的项目中使用时挂起

Mongodb driver with mongodb bson library causes completableFuture hangs when used in separate projects

我有一个项目,比方说 projectA,它有一个向客户公开其逻辑的 HTTP 组件。

在这个项目中有这样的代码:

void syncMethod() {
  CompletableFuture<Void> f = new CompletableFuture<>();
  someAsyncOperationThatReceivesACallback((Void x, Exception ex) -> {
    if(ex != null) f.completeExceptionally(ex);
    else f.complete(null); // An example of a result.
  });
  f.get(); // Wait unconditionally 
}

并且此代码有效,因为它等待操作完成,并且未来使用异步操作的结果完成。

需要在 2 个 webapp 之间共享逻辑,所以我将 projectA 分成了 2 个项目,假设 projectA-LOGICprojectA-HTTP 其中 projectA-HTTP.dependsOn(projectA-LOGIC)

projectA-HTTP 中有入口点,在 projectA-LOGIC 的打包 JAR 中有上面的代码 上面的代码停止完成,这意味着未来是从未完成,应用程序就在那里。

但是,如果我在 projectA-LOGIC 和 运行 中创建一个入口点,上面的代码一切正常。

我不明白这里发生的魔法。目前正在使用 jdk8_111。上面抽象出来的异步操作来自mongodb async driver and is listCollectionNames。当我有 2 个项目时,我尝试使用期货进行同步的所有异步(通过回调)操作都会遇到相同的行为。

编辑:

线程转储:

完整线程转储

"main@1" prio=5 tid=0x1 nid=NA waiting
  java.lang.Thread.State: WAITING
      at sun.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
      at java.util.concurrent.CompletableFuture$Signaller.block(CompletableFuture.java:1693)
      at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3323)
      at java.util.concurrent.CompletableFuture.waitingGet(CompletableFuture.java:1729)
      at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)

"cluster-ClusterId{value='588bc56a32de912224244114', description='null'}-127.0.0.1:27017@4072" daemon prio=5 tid=0xf nid=NA waiting
  java.lang.Thread.State: WAITING
      at sun.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
      at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.waitForSignalOrTimeout(DefaultServerMonitor.java:238)
      at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.waitForNext(DefaultServerMonitor.java:219)
      at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:168)
      - locked <0x10fe> (a com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable)
      at java.lang.Thread.run(Thread.java:745)

"cluster-588bc56a32de912224244114@4283" daemon prio=5 tid=0x15 nid=NA waiting
  java.lang.Thread.State: WAITING
      at sun.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos(AbstractQueuedSynchronizer.java:1037)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(AbstractQueuedSynchronizer.java:1328)
      at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:277)
      at com.mongodb.connection.BaseCluster$WaitQueueHandler.run(BaseCluster.java:464)
      at java.lang.Thread.run(Thread.java:745)

"Thread-6@4227" daemon prio=5 tid=0x14 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at sun.nio.ch.Iocp.getQueuedCompletionStatus(Iocp.java:-1)
      at sun.nio.ch.Iocp.access0(Iocp.java:46)
      at sun.nio.ch.Iocp$EventHandlerTask.run(Iocp.java:333)
      at sun.nio.ch.AsynchronousChannelGroupImpl.run(AsynchronousChannelGroupImpl.java:112)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at java.lang.Thread.run(Thread.java:745)

"Thread-5@4225" daemon prio=5 tid=0x13 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at sun.nio.ch.Iocp.getQueuedCompletionStatus(Iocp.java:-1)
      at sun.nio.ch.Iocp.access0(Iocp.java:46)
      at sun.nio.ch.Iocp$EventHandlerTask.run(Iocp.java:333)
      at sun.nio.ch.AsynchronousChannelGroupImpl.run(AsynchronousChannelGroupImpl.java:112)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at java.lang.Thread.run(Thread.java:745)

"Thread-4@4224" daemon prio=5 tid=0x12 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at sun.nio.ch.Iocp.getQueuedCompletionStatus(Iocp.java:-1)
      at sun.nio.ch.Iocp.access0(Iocp.java:46)
      at sun.nio.ch.Iocp$EventHandlerTask.run(Iocp.java:333)
      at sun.nio.ch.AsynchronousChannelGroupImpl.run(AsynchronousChannelGroupImpl.java:112)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at java.lang.Thread.run(Thread.java:745)

"Thread-3@4217" daemon prio=5 tid=0x11 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at sun.nio.ch.Iocp.getQueuedCompletionStatus(Iocp.java:-1)
      at sun.nio.ch.Iocp.access0(Iocp.java:46)
      at sun.nio.ch.Iocp$EventHandlerTask.run(Iocp.java:333)
      at sun.nio.ch.AsynchronousChannelGroupImpl.run(AsynchronousChannelGroupImpl.java:112)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at java.lang.Thread.run(Thread.java:745)

"Thread-2@4216" daemon prio=5 tid=0x10 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at sun.nio.ch.Iocp.getQueuedCompletionStatus(Iocp.java:-1)
      at sun.nio.ch.Iocp.access0(Iocp.java:46)
      at sun.nio.ch.Iocp$EventHandlerTask.run(Iocp.java:333)
      at java.lang.Thread.run(Thread.java:745)

"Finalizer@4348" daemon prio=8 tid=0x3 nid=NA waiting
  java.lang.Thread.State: WAITING
      at java.lang.Object.wait(Object.java:-1)
      at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
      at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
      at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler@4349" daemon prio=10 tid=0x2 nid=NA waiting
  java.lang.Thread.State: WAITING
      at java.lang.Object.wait(Object.java:-1)
      at java.lang.Object.wait(Object.java:502)
      at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
      at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"Attach Listener@4346" daemon prio=5 tid=0x5 nid=NA runnable
  java.lang.Thread.State: RUNNABLE

"Signal Dispatcher@4347" daemon prio=9 tid=0x4 nid=NA runnable
  java.lang.Thread.State: RUNNABLE

我不明白的是,仅仅将代码拆分到单独的项目中怎么会发生这种情况。认为我遗漏了一些关于 CompletableFutures 的微妙细节...

事实证明,这个问题比我想象的要简单得多,而且(愚蠢)。

我使用的是 mongodb 异步驱动程序 v3.2.1 和 mongodb bson 库 v3.4.1。事实证明,当我将 bson 库的版本更改为 v3.2.1 时,一切正常。