reactor / BlockHound

Java agent to detect blocking calls from non-blocking threads.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BlockHound does not flag Thread.sleep(long, int) since JDK 21

Badbond opened this issue · comments

With the introduction of Virtual Threads in JDK 21, the implementation of the Thread class has changed. As such, invocations of Thread.sleep(long, int) are no longer flagged by BlockHound. Note that TimeUnit.sleep also invokes this method.

Expected Behavior

Invocations of Thread.sleep(long, int) are flagged.

Actual Behavior

Invocations of Thread.sleep(long, int) are not flagged.

Steps to Reproduce

Consider the following JUnit test. This test passes on JDK <= 20, but fails for JDK 21.

  @Test
  void threadSleepInvocation() {
    BlockHound.install();
    Mono.fromRunnable(
            () -> {
              try {
                Thread.sleep(1, 1);
              } catch (InterruptedException e) {
                fail(e);
              }
            })
        .subscribeOn(Schedulers.parallel())
        .as(StepVerifier::create)
        .verifyErrorSatisfies(
            throwable ->
                assertThat(throwable)
                    .isInstanceOf(BlockingOperationError.class)
                    .hasMessageContaining("java.lang.Thread.sleep"));
  }

Possible Solution

With JDK <= 20, Thread.sleep(long, int) would call Thread.sleep(long) and as such both usages would be flagged.

With JDK >= 21, both methods call Thread.sleep0(long) (iff not a VirtualThread). Similar to conditionally adding signatures for JDK >= 9, we can add the signature for sleep0(J)V for JDK >= 21. However, I am not yet familiar with the stance of Reactor on the severity of blocking calls in virtual threads, given the recent virtual threads support of BoundedElasticScheduler. Perhaps a different strategy should be taken into account for virtual threads more widely.

I am eager to contribute a PR if simply flagging Thread.sleep0(long, int) invocations is acceptable.

Your Environment

Dependencies:

  • BlockHound: 1.0.8.RELEASE
  • Reactor BOM: 2023.0.2
  • ByteBuddy Parent: 1.14.11

JVM version (java -version):

openjdk version "21.0.2" 2024-01-16 LTS
OpenJDK Runtime Environment Temurin-21.0.2+13 (build 21.0.2+13-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.2+13 (build 21.0.2+13-LTS, mixed mode, sharing)

OS and version (eg uname -a):

Linux PDSoels-Latitude-5421 5.15.0-91-generic #101~20.04.1-Ubuntu SMP Thu Nov 16 14:22:28 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

@Badbond , thanks for reporting, I will take a look.

@Badbond ,

That would be great if you want to contribute! indeed, looking at Thread.java from jdk21, a kind of put("sleep0", singleton("(J)V")); should resolve the issue.

Regarding virtual threads, if I'm correct, boundedElastic() runs tasks on virtual threads , but BlockHound do not check blocking methods from boundedElastic() threads, so it should be ok.
In any case, if there are other issues related to loom that need to be addressed, we can do it in some other PRs, so feel free to go ahead with a PR that is fixing this current issue.

thanks !