diff --git a/src/main/java/com/thealgorithms/sorts/ConcurrentMergeSort.java b/src/main/java/com/thealgorithms/sorts/ConcurrentMergeSort.java
new file mode 100644
index 000000000000..062da01f380e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/sorts/ConcurrentMergeSort.java
@@ -0,0 +1,145 @@
+package com.thealgorithms.sorts;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A concurrent implementation of the Merge Sort algorithm.
+ *
+ *
This implementation utilizes a divide-and-conquer strategy, distributing
+ * the sorting of sub-arrays across multiple threads using a {@link ThreadPoolExecutor}.
+ * To prevent the overhead of thread creation and context switching from outweighing
+ * the benefits of concurrency, it falls back to a standard sequential merge sort
+ * when the sub-array size drops below a predefined threshold, or when the maximum
+ * concurrency depth is reached (preventing thread starvation deadlocks).
+ *
+ *
Complexity:
+ *
+ * - Time Complexity: $O(N \log N)$
+ * - Space Complexity: $O(N)$
+ *
+ */
+public final class ConcurrentMergeSort {
+
+ private ConcurrentMergeSort() {
+ }
+
+ /**
+ * Fallback threshold where the algorithm switches to standard sequential
+ * Merge Sort to prevent thread-creation overhead from ruining performance.
+ */
+ private static final int SEQUENTIAL_THRESHOLD = 8192;
+
+ /**
+ * Sorts the specified array of integers concurrently using Merge Sort.
+ *
+ * @param array the array to be sorted
+ */
+ public static void sort(int[] array) {
+ if (array == null || array.length <= 1) {
+ return;
+ }
+
+ int availableProcessors = Runtime.getRuntime().availableProcessors();
+
+ // Calculate a safe maximum depth to prevent creating more tasks than the pool can handle.
+ // This effectively prevents thread starvation deadlock in fixed-size thread pools,
+ // by forcing leaf tasks to run sequentially and eventually complete.
+ int maxDepth = (int) (Math.log(availableProcessors) / Math.log(2)) + 1;
+
+ ThreadPoolExecutor executor = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
+
+ try {
+ int[] tempArray = new int[array.length];
+ concurrentMergeSort(array, tempArray, 0, array.length - 1, executor, maxDepth);
+ } finally {
+ // Ensure the executor is gracefully shut down
+ executor.shutdown();
+ }
+ }
+
+ /**
+ * Recursively sorts the array utilizing the provided executor for concurrency.
+ *
+ * @param array the array to sort
+ * @param temp a temporary array for merging
+ * @param left the starting index of the sub-array
+ * @param right the ending index of the sub-array
+ * @param executor the {@link ThreadPoolExecutor} to handle concurrent tasks
+ * @param depth the remaining depth for allowing concurrent execution
+ */
+ private static void concurrentMergeSort(int[] array, int[] temp, int left, int right, ThreadPoolExecutor executor, int depth) {
+ int length = right - left + 1;
+
+ // Switch to sequential sort if the array is small or we have reached the maximum concurrent depth
+ if (length < SEQUENTIAL_THRESHOLD || depth <= 0) {
+ sequentialMergeSort(array, temp, left, right);
+ return;
+ }
+
+ int mid = left + (right - left) / 2;
+
+ // Submit the left half for concurrent execution
+ CompletableFuture leftTask = CompletableFuture.runAsync(() -> concurrentMergeSort(array, temp, left, mid, executor, depth - 1), executor);
+
+ // Process the right half in the current thread to optimize resource usage
+ concurrentMergeSort(array, temp, mid + 1, right, executor, depth - 1);
+
+ // Wait for the concurrently executed left half to complete
+ leftTask.join();
+
+ merge(array, temp, left, mid, right);
+ }
+
+ /**
+ * Sorts the specified sub-array sequentially using standard Merge Sort.
+ *
+ * @param array the array to sort
+ * @param temp a temporary array for merging
+ * @param left the starting index of the sub-array
+ * @param right the ending index of the sub-array
+ */
+ private static void sequentialMergeSort(int[] array, int[] temp, int left, int right) {
+ if (left >= right) {
+ return;
+ }
+
+ int mid = left + (right - left) / 2;
+ sequentialMergeSort(array, temp, left, mid);
+ sequentialMergeSort(array, temp, mid + 1, right);
+ merge(array, temp, left, mid, right);
+ }
+
+ /**
+ * Merges two sorted sub-arrays into a single sorted sub-array.
+ *
+ * @param array the original array containing the sub-arrays
+ * @param temp a temporary array used for merging
+ * @param left the starting index of the first sub-array
+ * @param mid the ending index of the first sub-array (and the partition point)
+ * @param right the ending index of the second sub-array
+ */
+ private static void merge(int[] array, int[] temp, int left, int mid, int right) {
+ System.arraycopy(array, left, temp, left, right - left + 1);
+
+ int i = left;
+ int j = mid + 1;
+ int k = left;
+
+ while (i <= mid && j <= right) {
+ if (temp[i] <= temp[j]) {
+ array[k++] = temp[i++];
+ } else {
+ array[k++] = temp[j++];
+ }
+ }
+
+ while (i <= mid) {
+ array[k++] = temp[i++];
+ }
+
+ // Remaining elements from the right half are already in their correct relative positions
+ }
+}
diff --git a/src/test/java/com/thealgorithms/sorts/ConcurrentMergeSortTest.java b/src/test/java/com/thealgorithms/sorts/ConcurrentMergeSortTest.java
new file mode 100644
index 000000000000..454d0bd26929
--- /dev/null
+++ b/src/test/java/com/thealgorithms/sorts/ConcurrentMergeSortTest.java
@@ -0,0 +1,93 @@
+package com.thealgorithms.sorts;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import java.util.Arrays;
+import java.util.Random;
+import org.junit.jupiter.api.Test;
+
+/**
+ * JUnit 5 test class for {@link ConcurrentMergeSort}.
+ */
+public class ConcurrentMergeSortTest {
+
+ @Test
+ public void testAlreadySortedArray() {
+ int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ int[] expected = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+ ConcurrentMergeSort.sort(array);
+
+ assertArrayEquals(expected, array, "Already sorted array should remain unchanged.");
+ }
+
+ @Test
+ public void testReverseSortedArray() {
+ int[] array = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ int[] expected = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+ ConcurrentMergeSort.sort(array);
+
+ assertArrayEquals(expected, array, "Reverse sorted array should be sorted correctly.");
+ }
+
+ @Test
+ public void testIdenticalElementsArray() {
+ int[] array = {5, 5, 5, 5, 5, 5, 5};
+ int[] expected = {5, 5, 5, 5, 5, 5, 5};
+
+ ConcurrentMergeSort.sort(array);
+
+ assertArrayEquals(expected, array, "Array with identical elements should be sorted correctly (unchanged).");
+ }
+
+ @Test
+ public void testLargeRandomArray() {
+ int size = 100_000;
+ int[] array = new int[size];
+ int[] expected = new int[size];
+ // Using a fixed seed for deterministic testing
+ Random random = new Random(42);
+
+ for (int i = 0; i < size; i++) {
+ int value = random.nextInt();
+ array[i] = value;
+ expected[i] = value;
+ }
+
+ // Generate the expected result using Java's highly optimized built-in sort
+ Arrays.sort(expected);
+
+ // This will easily trigger the concurrency threshold (8192) in the implementation
+ ConcurrentMergeSort.sort(array);
+
+ assertArrayEquals(expected, array, "Large random array should be sorted correctly utilizing concurrency.");
+ }
+
+ @Test
+ public void testEmptyArray() {
+ int[] array = {};
+ int[] expected = {};
+
+ ConcurrentMergeSort.sort(array);
+
+ assertArrayEquals(expected, array, "Empty array should be handled without errors.");
+ }
+
+ @Test
+ public void testSingleElementArray() {
+ int[] array = {42};
+ int[] expected = {42};
+
+ ConcurrentMergeSort.sort(array);
+
+ assertArrayEquals(expected, array, "Single element array should be handled without errors.");
+ }
+
+ @Test
+ public void testNullArray() {
+ int[] array = null;
+ ConcurrentMergeSort.sort(array);
+ org.junit.jupiter.api.Assertions.assertNull(array, "Null array should be handled without errors.");
+ }
+}