prevent synchronized blocking the virtual threads in JDK21

Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/CommittingOutputStream.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/CommittingOutputStream.java
index 39f74fb..7c1cf4a 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/CommittingOutputStream.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/CommittingOutputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -25,6 +25,7 @@
 
 import org.glassfish.jersey.internal.LocalizationMessages;
 import org.glassfish.jersey.internal.guava.Preconditions;
+import org.glassfish.jersey.internal.util.JdkVersion;
 
 /**
  * A committing output stream with optional serialized entity buffering functionality
@@ -58,6 +59,8 @@
 public final class CommittingOutputStream extends OutputStream {
 
     private static final Logger LOGGER = Logger.getLogger(CommittingOutputStream.class.getName());
+    private static final boolean JDK_21 = JdkVersion.getJdkVersion().getMajor() > 20;
+
     /**
      * Null stream provider.
      */
@@ -275,7 +278,13 @@
 
             commitStream(currentSize);
             if (buffer != null) {
-                buffer.writeTo(adaptedOutput);
+                if (adaptedOutput != null && JDK_21) {
+                    adaptedOutput.write(buffer.toByteArray());
+                } else {
+                    // Virtual thread in JDK 21 are blocked by synchronized writeTo
+                    // but about 10% faster than ^ without virtual threads.
+                    buffer.writeTo(adaptedOutput);
+                }
             }
         }
     }