title: Springboot and H2 shutdown deadlock
body: <p>Currently I'm able to create a deadlock when using the combination of h2 and spring boot. There's a lot of issues out there, that looks kind of similar, but apparently they have been solved, and I'm not entirely sure if it's Spring or h2 that does something strange.</p>
  
  <p>First off the visualvm trace for the deadlock (scroll to the bottom for the lock):</p>
  
  <pre><code>
  2019-07-08 12:34:47
  Full thread dump OpenJDK 64-Bit Server VM (25.212-b03 mixed mode):
  
  "RMI TCP Connection(2)-127.0.0.1" #25 daemon prio=9 os_prio=0 tid=0x00007fc19c0f6000 nid=0x2f44 runnable [0x00007fc1a2444000]
     java.lang.Thread.State: RUNNABLE
          at java.net.SocketInputStream.socketRead0(Native Method)
          at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
          at java.net.SocketInputStream.read(SocketInputStream.java:171)
          at java.net.SocketInputStream.read(SocketInputStream.java:141)
          at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
          at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
          - locked &lt;0x00000000f5c5bdb0&gt; (a java.io.BufferedInputStream)
          at java.io.FilterInputStream.read(FilterInputStream.java:83)
          at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$607/422104739.run(Unknown Source)
          at java.security.AccessController.doPrivileged(Native Method)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
          at java.lang.Thread.run(Thread.java:748)
  
     Locked ownable synchronizers:
          - &lt;0x00000000f58d4990&gt; (a java.util.concurrent.ThreadPoolExecutor$Worker)
  
  "JMX server connection timeout 24" #24 daemon prio=9 os_prio=0 tid=0x00007fc19804c000 nid=0x2f42 in Object.wait() [0x00007fc1a2746000]
     java.lang.Thread.State: TIMED_WAITING (on object monitor)
          at java.lang.Object.wait(Native Method)
          - waiting on &lt;0x00000000f59cafe0&gt; (a [I)
          at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
          - locked &lt;0x00000000f59cafe0&gt; (a [I)
          at java.lang.Thread.run(Thread.java:748)
  
     Locked ownable synchronizers:
          - None
  
  "RMI Scheduler(0)" #23 daemon prio=9 os_prio=0 tid=0x00007fc198039800 nid=0x2f41 waiting on condition [0x00007fc1a32fd000]
     java.lang.Thread.State: TIMED_WAITING (parking)
          at sun.misc.Unsafe.park(Native Method)
          - parking to wait for  &lt;0x00000000f5586878&gt; (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
          at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
          at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
          at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
          at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
          at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
          at java.lang.Thread.run(Thread.java:748)
  
     Locked ownable synchronizers:
          - None
  
  "RMI TCP Connection(1)-127.0.0.1" #22 daemon prio=9 os_prio=0 tid=0x00007fc19c57d800 nid=0x2f40 runnable [0x00007fc1a3dfd000]
     java.lang.Thread.State: RUNNABLE
          at java.net.SocketInputStream.socketRead0(Native Method)
          at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
          at java.net.SocketInputStream.read(SocketInputStream.java:171)
          at java.net.SocketInputStream.read(SocketInputStream.java:141)
          at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
          at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
          - locked &lt;0x00000000f598e720&gt; (a java.io.BufferedInputStream)
          at java.io.FilterInputStream.read(FilterInputStream.java:83)
          at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$607/422104739.run(Unknown Source)
          at java.security.AccessController.doPrivileged(Native Method)
          at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
          at java.lang.Thread.run(Thread.java:748)
  
     Locked ownable synchronizers:
          - &lt;0x00000000f58d4360&gt; (a java.util.concurrent.ThreadPoolExecutor$Worker)
  
  "RMI TCP Accept-0" #21 daemon prio=9 os_prio=0 tid=0x00007fc1ad3a9800 nid=0x2f3e runnable [0x00007fc1b47fb000]
     java.lang.Thread.State: RUNNABLE
          at java.net.PlainSocketImpl.socketAccept(Native Method)
          at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
          at java.net.ServerSocket.implAccept(ServerSocket.java:545)
          at java.net.ServerSocket.accept(ServerSocket.java:513)
          at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:52)
          at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:405)
          at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:377)
          at java.lang.Thread.run(Thread.java:748)
  
     Locked ownable synchronizers:
          - None
  
  "Attach Listener" #20 daemon prio=9 os_prio=0 tid=0x00007fc1c8001000 nid=0x2f3c waiting on condition [0x0000000000000000]
     java.lang.Thread.State: RUNNABLE
  
     Locked ownable synchronizers:
          - None
  
  "Thread-8" #19 prio=5 os_prio=0 tid=0x00007fc210870800 nid=0x2f06 waiting for monitor entry [0x00007fc1b4ffc000]
     java.lang.Thread.State: BLOCKED (on object monitor)
          at org.h2.command.dml.TransactionCommand.update(TransactionCommand.java:98)
          - waiting to lock &lt;0x00000000ff487080&gt; (a org.h2.engine.Session)
          at org.h2.command.CommandContainer.update(CommandContainer.java:133)
          at org.h2.command.Command.executeUpdate(Command.java:267)
          - locked &lt;0x00000000ff5dc0d0&gt; (a org.h2.engine.Session)
          at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:233)
          - locked &lt;0x00000000ff5dc0d0&gt; (a org.h2.engine.Session)
          at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:205)
          at org.springframework.jdbc.datasource.embedded.AbstractEmbeddedDatabaseConfigurer.shutdown(AbstractEmbeddedDatabaseConfigurer.java:47)
          at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory.shutdownDatabase(EmbeddedDatabaseFactory.java:228)
          at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory$EmbeddedDataSourceProxy.shutdown(EmbeddedDatabaseFactory.java:303)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:498)
          at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:337)
          at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:271)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:571)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:543)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1034)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:504)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1027)
          at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1057)
          at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1026)
          at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:945)
          - locked &lt;0x00000000ff2b55d0&gt; (a java.lang.Object)
  
     Locked ownable synchronizers:
          - None
  
  "Thread-6" #17 prio=5 os_prio=0 tid=0x00007fc2107e7000 nid=0x2f05 waiting for monitor entry [0x00007fc1b4efb000]
     java.lang.Thread.State: BLOCKED (on object monitor)
          at org.h2.command.dml.TransactionCommand.update(TransactionCommand.java:98)
          - waiting to lock &lt;0x00000000ff5dc0d0&gt; (a org.h2.engine.Session)
          at org.h2.command.CommandContainer.update(CommandContainer.java:133)
          at org.h2.command.Command.executeUpdate(Command.java:267)
          - locked &lt;0x00000000ff487080&gt; (a org.h2.engine.Session)
          at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:233)
          - locked &lt;0x00000000ff487080&gt; (a org.h2.engine.Session)
          at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:205)
          at org.springframework.jdbc.datasource.embedded.AbstractEmbeddedDatabaseConfigurer.shutdown(AbstractEmbeddedDatabaseConfigurer.java:47)
          at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory.shutdownDatabase(EmbeddedDatabaseFactory.java:228)
          at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory$EmbeddedDataSourceProxy.shutdown(EmbeddedDatabaseFactory.java:303)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:498)
          at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:337)
          at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:271)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:571)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:543)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1034)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:504)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1027)
          at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1057)
          at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1026)
          at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:945)
          - locked &lt;0x00000000e002b8d0&gt; (a java.lang.Object)
  
     Locked ownable synchronizers:
          - None
  
  "Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007fc210169800 nid=0x2ef5 runnable [0x0000000000000000]
     java.lang.Thread.State: RUNNABLE
  
     Locked ownable synchronizers:
          - None
  
  "C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00007fc210156000 nid=0x2ef4 waiting on condition [0x0000000000000000]
     java.lang.Thread.State: RUNNABLE
  
     Locked ownable synchronizers:
          - None
  
  "C2 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007fc210154000 nid=0x2ef3 waiting on condition [0x0000000000000000]
     java.lang.Thread.State: RUNNABLE
  
     Locked ownable synchronizers:
          - None
  
  "C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007fc210152000 nid=0x2ef2 waiting on condition [0x0000000000000000]
     java.lang.Thread.State: RUNNABLE
  
     Locked ownable synchronizers:
          - None
  
  "C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007fc210150000 nid=0x2ef1 waiting on condition [0x0000000000000000]
     java.lang.Thread.State: RUNNABLE
  
     Locked ownable synchronizers:
          - None
  
  "Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007fc21014d800 nid=0x2ef0 runnable [0x0000000000000000]
     java.lang.Thread.State: RUNNABLE
  
     Locked ownable synchronizers:
          - None
  
  "Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007fc21008c800 nid=0x2eef in Object.wait() [0x00007fc1e160c000]
     java.lang.Thread.State: WAITING (on object monitor)
          at java.lang.Object.wait(Native Method)
          - waiting on &lt;0x00000000e0016c68&gt; (a java.lang.ref.ReferenceQueue$Lock)
          at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
          - locked &lt;0x00000000e0016c68&gt; (a java.lang.ref.ReferenceQueue$Lock)
          at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
          at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
  
     Locked ownable synchronizers:
          - None
  
  "Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007fc21008a000 nid=0x2eee in Object.wait() [0x00007fc1e170d000]
     java.lang.Thread.State: WAITING (on object monitor)
          at java.lang.Object.wait(Native Method)
          - waiting on &lt;0x00000000e0016e38&gt; (a java.lang.ref.Reference$Lock)
          at java.lang.Object.wait(Object.java:502)
          at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
          - locked &lt;0x00000000e0016e38&gt; (a java.lang.ref.Reference$Lock)
          at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
  
     Locked ownable synchronizers:
          - None
  
  "main" #1 prio=5 os_prio=0 tid=0x00007fc21000b000 nid=0x2ee4 in Object.wait() [0x00007fc214f53000]
     java.lang.Thread.State: WAITING (on object monitor)
          at java.lang.Object.wait(Native Method)
          - waiting on &lt;0x00000000ff24cda8&gt; (a org.springframework.context.support.AbstractApplicationContext$1)
          at java.lang.Thread.join(Thread.java:1252)
          - locked &lt;0x00000000ff24cda8&gt; (a org.springframework.context.support.AbstractApplicationContext$1)
          at java.lang.Thread.join(Thread.java:1326)
          at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:107)
          at java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46)
          at java.lang.Shutdown.runHooks(Shutdown.java:123)
          at java.lang.Shutdown.sequence(Shutdown.java:167)
          at java.lang.Shutdown.exit(Shutdown.java:212)
          - locked &lt;0x00000000e039fcc8&gt; (a java.lang.Class for java.lang.Shutdown)
          at java.lang.Runtime.exit(Runtime.java:109)
          at java.lang.System.exit(System.java:971)
          at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:68)
  
     Locked ownable synchronizers:
          - None
  
  "VM Thread" os_prio=0 tid=0x00007fc210080000 nid=0x2eed runnable 
  
  "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007fc210020000 nid=0x2ee5 runnable 
  
  "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007fc210021800 nid=0x2ee6 runnable 
  
  "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007fc210023800 nid=0x2ee7 runnable 
  
  "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007fc210025000 nid=0x2ee8 runnable 
  
  "GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007fc210027000 nid=0x2ee9 runnable 
  
  "GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007fc210028800 nid=0x2eea runnable 
  
  "GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007fc21002a800 nid=0x2eeb runnable 
  
  "GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007fc21002c000 nid=0x2eec runnable 
  
  "VM Periodic Task Thread" os_prio=0 tid=0x00007fc21016c000 nid=0x2ef6 waiting on condition 
  
  JNI global references: 1324
  
  
  Found one Java-level deadlock:
  =============================
  "Thread-8":
    waiting to lock monitor 0x00007fc1ad3792c8 (object 0x00000000ff487080, a org.h2.engine.Session),
    which is held by "Thread-6"
  "Thread-6":
    waiting to lock monitor 0x00007fc1ad377cc8 (object 0x00000000ff5dc0d0, a org.h2.engine.Session),
    which is held by "Thread-8"
  
  Java stack information for the threads listed above:
  ===================================================
  "Thread-8":
          at org.h2.command.dml.TransactionCommand.update(TransactionCommand.java:98)
          - waiting to lock &lt;0x00000000ff487080&gt; (a org.h2.engine.Session)
          at org.h2.command.CommandContainer.update(CommandContainer.java:133)
          at org.h2.command.Command.executeUpdate(Command.java:267)
          - locked &lt;0x00000000ff5dc0d0&gt; (a org.h2.engine.Session)
          at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:233)
          - locked &lt;0x00000000ff5dc0d0&gt; (a org.h2.engine.Session)
          at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:205)
          at org.springframework.jdbc.datasource.embedded.AbstractEmbeddedDatabaseConfigurer.shutdown(AbstractEmbeddedDatabaseConfigurer.java:47)
          at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory.shutdownDatabase(EmbeddedDatabaseFactory.java:228)
          at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory$EmbeddedDataSourceProxy.shutdown(EmbeddedDatabaseFactory.java:303)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:498)
          at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:337)
          at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:271)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:571)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:543)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1034)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:504)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1027)
          at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1057)
          at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1026)
          at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:945)
          - locked &lt;0x00000000ff2b55d0&gt; (a java.lang.Object)
  "Thread-6":
          at org.h2.command.dml.TransactionCommand.update(TransactionCommand.java:98)
          - waiting to lock &lt;0x00000000ff5dc0d0&gt; (a org.h2.engine.Session)
          at org.h2.command.CommandContainer.update(CommandContainer.java:133)
          at org.h2.command.Command.executeUpdate(Command.java:267)
          - locked &lt;0x00000000ff487080&gt; (a org.h2.engine.Session)
          at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:233)
          - locked &lt;0x00000000ff487080&gt; (a org.h2.engine.Session)
          at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:205)
          at org.springframework.jdbc.datasource.embedded.AbstractEmbeddedDatabaseConfigurer.shutdown(AbstractEmbeddedDatabaseConfigurer.java:47)
          at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory.shutdownDatabase(EmbeddedDatabaseFactory.java:228)
          at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory$EmbeddedDataSourceProxy.shutdown(EmbeddedDatabaseFactory.java:303)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:498)
          at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:337)
          at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:271)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:571)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:543)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1034)
          at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:504)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1027)
          at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1057)
          at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1026)
          at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:945)
          - locked &lt;0x00000000e002b8d0&gt; (a java.lang.Object)
  
  Found 1 deadlock.
  </code></pre>
  
  <p>When tracing into the files in the lock trace it seems quite clear that it locks during Shutdown. To reproduce the following code was set up:</p>
  
  <p>Application.kt</p>
  
  <pre><code>package com.example.deadlock
  
  import org.springframework.boot.SpringApplication
  import org.springframework.boot.autoconfigure.SpringBootApplication
  import org.springframework.context.annotation.Bean
  import org.springframework.context.annotation.Configuration
  import org.springframework.jdbc.core.JdbcTemplate
  
  @SpringBootApplication
  @Configuration
  open class Application {
      @Bean
      open fun repository(jdbcTemplate: JdbcTemplate): Repository {
          return Repository(jdbcTemplate)
      }
  
      companion object {
          @JvmStatic
          fun main(args: Array&lt;String&gt;) {
              SpringApplication.run(Application::class.java, *args)
          }
      }
  }
  </code></pre>
  
  <p>Repository.kt</p>
  
  <pre><code>package com.example.deadlock
  
  import org.springframework.jdbc.core.JdbcTemplate
  
  class Repository constructor(private val template: JdbcTemplate) {
      fun findAll(): List&lt;String&gt; =
          template.queryForList("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='jfdksaiufd'", String::class.java)
  }
  </code></pre>
  
  <p>Controller.kt</p>
  
  <pre><code>package com.example.deadlock
  
  import org.springframework.http.MediaType
  import org.springframework.web.bind.annotation.GetMapping
  import org.springframework.web.bind.annotation.RequestMapping
  import org.springframework.web.bind.annotation.RestController
  
  @RestController
  @RequestMapping(path = ["/foo"],
          produces = [MediaType.APPLICATION_JSON_UTF8_VALUE])
  class Controller(private val repository: Repository) {
      @GetMapping
      fun banks(): List&lt;String&gt; {
          val banks = repository.findAll()
          return emptyList()
      }
  }
  </code></pre>
  
  <p>To reproduce the error, the follow combination of tests seems to be the minimum usable:</p>
  
  <p>EndpointTest.kt</p>
  
  <pre><code>package com.example.deadlock
  
  import org.junit.jupiter.api.Test
  import org.springframework.beans.factory.annotation.Autowired
  import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
  import org.springframework.boot.test.context.SpringBootTest
  import org.springframework.http.MediaType
  import org.springframework.test.web.servlet.MockMvc
  import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
  import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
  import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
  
  @SpringBootTest(classes = [Application::class])
  @AutoConfigureMockMvc
  class EndpointTest @Autowired constructor(private val mockMvc: MockMvc) {
      @Test
      fun empty() {
          val mvcRequest = MockMvcRequestBuilders.get("/foo").accept(MediaType.APPLICATION_JSON_UTF8)
          mockMvc.perform(mvcRequest)
                  .andExpect(status().isOk)
                  .andExpect(content().string("[]"))
      }
  }
  </code></pre>
  
  <p>RepositoryTest.kt</p>
  
  <pre><code>package com.example.deadlock
  
  import org.junit.jupiter.api.Test
  import org.springframework.beans.factory.annotation.Autowired
  import org.springframework.boot.test.context.SpringBootTest
  import kotlin.test.assertEquals
  
  @SpringBootTest(classes = [Application::class])
  class RepositoryTest @Autowired constructor(private val repository: Repository) {
      @Test
      fun initialCount() {
          assertEquals(0, repository.findAll().size)
      }
  }
  </code></pre>
  
  <p>For the sake of completeness this is the build.gradle in question:</p>
  
  <pre><code>buildscript {
      ext {
          kotlinVersion = "1.3.31"
          springVersion = "2.1.5.RELEASE"
      }
      repositories {
          mavenCentral()
      }
      dependencies {
          classpath "org.springframework.boot:spring-boot-gradle-plugin:${springVersion}"
      }
  }
  
  plugins {
      id "org.jetbrains.kotlin.jvm" version "1.3.31"
      id "org.springframework.boot" version "2.1.5.RELEASE"
  
      id "idea"
  }
  
  apply plugin: "org.springframework.boot"
  apply plugin: "io.spring.dependency-management"
  
  group = "com.example.deadlock"
  version = "0.0.1-SNAPSHOT"
  description = "Deadlock with Spring and h2"
  sourceCompatibility = JavaVersion.VERSION_1_8
  targetCompatibility = JavaVersion.VERSION_1_8
  compileJava.options.encoding = "UTF-8"
  
  tasks.withType(Test) {
      useJUnitPlatform()
      outputs.upToDateWhen {false}
  }
  
  repositories {
      mavenCentral()
  }
  
  dependencies {
      implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
      implementation "org.jetbrains.kotlin:kotlin-reflect"
      testImplementation "org.jetbrains.kotlin:kotlin-test"
      testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
  
      compile "org.springframework.boot:spring-boot-starter-web"
      compile "org.springframework:spring-jdbc"
  
      compile "com.h2database:h2"
  
      // Test setups
      testCompile "org.junit.jupiter:junit-jupiter-api"
      testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine"
  
      testCompile "org.springframework.boot:spring-boot-starter-test"
  }
  </code></pre>
  
  <p>And at least on my machine it's easily reproducible by running <code>./gradlew clean assemble</code> followed by doing a looped <code>./gradlew test</code>.</p>
  
  <p>For some reason it does not work if the two tests are identical, and (not surprisingly) I haven't been able to reproduce with only one test.</p>
  
  <p>From what I can see it could look like that there are two shutdown hooks that end up competing about closing the issue. However, I am not entirely certain.</p>