--- old/src/share/vm/classfile/symbolTable.cpp	2020-05-19 11:21:23.590525147 +0200
+++ new/src/share/vm/classfile/symbolTable.cpp	2020-05-19 11:21:23.510525171 +0200
@@ -926,6 +926,28 @@
   }
 }
 
+void StringTable::possibly_parallel_oops_do_shenandoah(OopClosure* f) {
+  const int limit = the_table()->table_size();
+
+  // ClaimChunkSize is too small for processing a String table during the pause
+  // efficiently: the atomic add costs dominate on many reasonable string tables.
+  // Recast the chunk size to give each GC worker about 10 chunks.
+  assert(UseShenandoahGC, "Only for Shenandoah");
+  const int chunk_size = limit / (ParallelGCThreads * 10);
+
+  for (;;) {
+    // Grab next set of buckets to scan
+    int start_idx = Atomic::add(chunk_size, &_parallel_claimed_idx) - chunk_size;
+    if (start_idx >= limit) {
+      // End of table
+      break;
+    }
+
+    int end_idx = MIN2(limit, start_idx + chunk_size);
+    buckets_oops_do(f, start_idx, end_idx);
+  }
+}
+
 // This verification is part of Universe::verify() and needs to be quick.
 // See StringTable::verify_and_compare() below for exhaustive verification.
 void StringTable::verify() {
--- old/src/share/vm/classfile/symbolTable.hpp	2020-05-19 11:21:24.090525000 +0200
+++ new/src/share/vm/classfile/symbolTable.hpp	2020-05-19 11:21:24.006525025 +0200
@@ -328,6 +328,7 @@
     possibly_parallel_unlink_or_oops_do(cl, NULL, processed, removed);
   }
   static void possibly_parallel_oops_do(OopClosure* f);
+  static void possibly_parallel_oops_do_shenandoah(OopClosure* f);
 
   // Hashing algorithm, used as the hash value used by the
   //     StringTable for bucket selection and comparison (stored in the
--- old/src/share/vm/gc_implementation/shenandoah/shenandoahRootProcessor.cpp	2020-05-19 11:21:24.586524855 +0200
+++ new/src/share/vm/gc_implementation/shenandoah/shenandoahRootProcessor.cpp	2020-05-19 11:21:24.502524880 +0200
@@ -103,7 +103,7 @@
 
 void ShenandoahStringTableRoots::oops_do(OopClosure* oops, uint worker_id) {
   ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::StringTableRoots, worker_id);
-  StringTable::possibly_parallel_oops_do(oops);
+  StringTable::possibly_parallel_oops_do_shenandoah(oops);
 }
 
 ShenandoahThreadRoots::ShenandoahThreadRoots(ShenandoahPhaseTimings::Phase phase) :