---
 src/hotspot/share/prims/unsafe.cpp            |  6 ++++++
 src/hotspot/share/runtime/globals.hpp         |  5 +++++
 .../share/classes/java/lang/StringUTF16.java  | 19 +++++++++++++++++++
 .../classes/jdk/internal/misc/Unsafe.java     |  1 +
 4 files changed, 31 insertions(+)

diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp
index 91328cd19..37d46225f 100644
--- a/src/hotspot/share/prims/unsafe.cpp
+++ b/src/hotspot/share/prims/unsafe.cpp
@@ -1007,6 +1007,11 @@ UNSAFE_ENTRY(jint, Unsafe_GetLoadAverage0(JNIEnv *env, jobject unsafe, jdoubleAr
   return ret;
 } UNSAFE_END
 
+UNSAFE_ENTRY(jboolean, Unsafe_GetUseCharCache(JNIEnv *env, jobject unsafe)) {
+  return UseCharCache;
+}
+UNSAFE_END
+
 UNSAFE_ENTRY(jboolean, Unsafe_GetUseHashMapIntegerCache(JNIEnv *env, jobject unsafe)) {
   return UseHashMapIntegerCache;
 }
@@ -1102,6 +1107,7 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = {
     {CC "isBigEndian0",       CC "()Z",                  FN_PTR(Unsafe_isBigEndian0)},
     {CC "unalignedAccess0",   CC "()Z",                  FN_PTR(Unsafe_unalignedAccess0)},
 
+    {CC "getUseCharCache", CC "()Z",                     FN_PTR(Unsafe_GetUseCharCache)},
     {CC "getUseHashMapIntegerCache", CC "()Z",           FN_PTR(Unsafe_GetUseHashMapIntegerCache)},
     {CC "getUseFastSerializer",   CC "()Z",              FN_PTR(Unsafe_GetUseFastSerializer)},
 
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
index e2bfd0c5b..40acb29b4 100644
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -2691,6 +2691,11 @@ define_pd_global(uint64_t,MaxRAM,                    1ULL*G);
           "the HashMap Value type, indexed by the unboxed int key value."   \
           "faster in execution, higher in memory consumption.")             \
                                                                             \
+  experimental(bool, UseCharCache, false,                                   \
+          "When char[] is frequently used to build strings, "               \
+          "and char[] has a lot of duplicate data, using char cache can"    \
+          "greatly improve performance and take up little extra space")     \
+                                                                            \
   experimental(bool, UseFastSerializer, false,                              \
           "Cache-based serialization.It is extremely fast, but it can only" \
           "be effective in certain scenarios.")                             \
diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java
index 331b51812..c3ede9676 100644
--- a/src/java.base/share/classes/java/lang/StringUTF16.java
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java
@@ -28,11 +28,13 @@ package java.lang;
 import java.util.Arrays;
 import java.util.Locale;
 import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
 import java.util.function.IntConsumer;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.vm.annotation.ForceInline;
 import jdk.internal.vm.annotation.DontInline;
 
@@ -41,6 +43,14 @@ import static java.lang.String.LATIN1;
 
 final class StringUTF16 {
 
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+    private static boolean enableCharCache = UNSAFE.getUseCharCache();
+
+    private static final int MAX_CHAR_CACHE = 1200000;
+
+    private static transient ConcurrentHashMap<char[], byte[]> charCache = new ConcurrentHashMap<>();
+
     public static byte[] newBytesFor(int len) {
         if (len < 0) {
             throw new NegativeArraySizeException();
@@ -157,8 +167,17 @@ final class StringUTF16 {
     }
 
     public static byte[] compress(char[] val, int off, int len) {
+        boolean flag = (off == 0 && len == val.length);
+        if(enableCharCache && flag) {
+            if(charCache.containsKey(val)) {
+                return charCache.get(val);
+            }
+        }
         byte[] ret = new byte[len];
         if (compress(val, off, ret, 0, len) == len) {
+            if(enableCharCache && flag && charCache.size() < MAX_CHAR_CACHE) {
+                charCache.put(val, ret);
+            }
             return ret;
         }
         return null;
diff --git a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
index 4d71e671e..4fc4b1a43 100644
--- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
+++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
@@ -3702,6 +3702,7 @@ public final class Unsafe {
     private static int convEndian(boolean big, int n)     { return big == BE ? n : Integer.reverseBytes(n)  ; }
     private static long convEndian(boolean big, long n)   { return big == BE ? n : Long.reverseBytes(n)     ; }
 
+    public native boolean getUseCharCache();
     public native boolean getUseHashMapIntegerCache();
     public native boolean getUseFastSerializer();
     private native long allocateMemory0(long bytes);
-- 
2.19.1