diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 0a7b261..9e0de11 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -2288,15 +2288,6 @@ function comment_alphadecimal_to_int($c = '00') {
 }
 
 /**
- * Increments a sorting code to the next value.
- *
- * @see comment_int_to_alphadecimal()
- */
-function comment_increment_alphadecimal($c = '00') {
-  return comment_int_to_alphadecimal(comment_alphadecimal_to_int($c) + 1);
-}
-
-/**
  * Implements hook_action_info().
  */
 function comment_action_info() {
diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
index b041ebd..5f0ea78 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
@@ -50,7 +50,7 @@ class CommentStorageController extends DatabaseStorageController {
    * Overrides Drupal\entity\DatabaseStorageController::preSave().
    *
    * @see comment_int_to_alphadecimal()
-   * @see comment_increment_alphadecimal()
+   * @see comment_alphadecimal_to_int()
    */
   protected function preSave(EntityInterface $comment) {
     global $user;
@@ -69,47 +69,55 @@ class CommentStorageController extends DatabaseStorageController {
       if (!empty($comment->thread)) {
         // Allow calling code to set thread itself.
         $thread = $comment->thread;
-      }
-      elseif ($comment->pid == 0) {
-        // This is a comment with no parent comment (depth 0): we start
-        // by retrieving the maximum thread level.
-        $max = db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid))->fetchField();
-        // Strip the "/" from the end of the thread.
-        $max = rtrim($max, '/');
-        // We need to get the value at the correct depth.
-        $parts = explode('.', $max);
-        $firstsegment = $parts[0];
-        // Finally, build the thread field for this new comment.
-        $thread = comment_increment_alphadecimal($firstsegment) .'/';
+        $need_lock = FALSE;
       }
       else {
-        // This is a comment with a parent comment, so increase the part of
-        // the thread value at the proper depth.
-
-        // Get the parent comment:
-        $parent = comment_load($comment->pid);
-        // Strip the "/" from the end of the parent thread.
-        $parent->thread = (string) rtrim((string) $parent->thread, '/');
-        // Get the max value in *this* thread.
-        $max = db_query("SELECT MAX(thread) FROM {comment} WHERE thread LIKE :thread AND nid = :nid", array(
-          ':thread' => $parent->thread . '.%',
-          ':nid' => $comment->nid,
-        ))->fetchField();
-
-        if ($max == '') {
-          // First child of this parent.
-          $thread = $parent->thread . '.' . comment_int_to_alphadecimal(0) . '/';
-        }
-        else {
-          // Strip the "/" at the end of the thread.
+        $prefix = '';
+        $need_lock = TRUE;
+        if ($comment->pid == 0) {
+          // This is a comment with no parent comment (depth 0): we start
+          // by retrieving the maximum thread level.
+          $max = db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid))->fetchField();
+          // Strip the "/" from the end of the thread.
           $max = rtrim($max, '/');
-          // Get the value at the correct depth.
+          // We need to get the value at the correct depth.
           $parts = explode('.', $max);
-          $parent_depth = count(explode('.', $parent->thread));
-          $last = $parts[$parent_depth];
-          // Finally, build the thread field for this new comment.
-          $thread = $parent->thread . '.' . comment_increment_alphadecimal($last) . '/';
+          $n = comment_alphadecimal_to_int($parts[0]);
+        }
+        else {
+          // This is a comment with a parent comment, so increase the part of
+          // the thread value at the proper depth.
+
+          // Get the parent comment:
+          $parent = comment_load($comment->pid);
+          // Strip the "/" from the end of the parent thread.
+          $parent->thread = (string) rtrim((string) $parent->thread, '/');
+          // Get the max value in *this* thread.
+          $max = db_query("SELECT MAX(thread) FROM {comment} WHERE thread LIKE :thread AND nid = :nid", array(
+            ':thread' => $parent->thread . '.%',
+            ':nid' => $comment->nid,
+          ))->fetchField();
+
+          if ($max == '') {
+            // First child of this parent.
+            $n = -1;
+          }
+          else {
+            // Strip the "/" at the end of the thread.
+            $max = rtrim($max, '/');
+            // Get the value at the correct depth.
+            $parts = explode('.', $max);
+            $parent_depth = count(explode('.', $parent->thread));
+            $n = comment_alphadecimal_to_int($parts[$parent_depth]);
+            $prefix = $parent->thread . '.';
+          }
         }
+        // Finally, build the thread field for this new comment. To avoid
+        // race conditions, get a lock on the thread. If aother process already
+        // has the lock, just increment the thread number.
+        do {
+          $thread = $prefix . comment_int_to_alphadecimal(++$n) . '/';
+        } while (!lock_acquire("comment:$comment->nid:$thread"));
       }
       if (empty($comment->created)) {
         $comment->created = REQUEST_TIME;
