You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java多线程快速排序CPU利用率无法达100%问题排查求助

Why Your Multi-Threaded Quicksort Isn't Using 100% CPU (And Fixes)

Let's walk through the issues in your code that are holding back CPU utilization, then fix them step by step:

1. You're Creating Way Too Many Threads (And Paying a Huge Overhead)

Right now, every time you split the array, you spawn two new threads—even for tiny subarrays (like a few hundred elements). Thread creation isn't free: it takes time to allocate stack space, register the thread with the OS, and handle scheduling. For small arrays, the time spent creating threads is way longer than the time spent sorting the elements themselves.

Worse, having hundreds or thousands of threads running at once forces your CPU to spend most of its time switching between threads (context switching) instead of actually doing sorting work. That's why your CPU is stuck at 40%—it's busy juggling threads, not computing.

2. You're Not Waiting for Threads to Finish

Your main thread starts the initial sort thread and immediately exits. While the JVM will keep running non-daemon threads, you have no way to confirm when sorting finishes, and the unregulated thread spawning leads to chaotic scheduling that hurts efficiency.

3. No Threshold for Single-Threaded Sorting

Multi-threading only makes sense for large chunks of work. For small subarrays, single-threaded sorting (even a simple insertion sort!) is faster because you avoid all the thread overhead.


Fixed Code Example

Here's how to adjust your code to fix these issues:

First, Update the SortThread Class

We'll add a threshold for single-threaded sorting, wait for child threads to finish, and avoid spawning threads for tiny arrays:

public class SortThread implements Runnable {
    private int[] arr;
    private int start;
    private int end;
    // Threshold: use single-threaded sort for subarrays smaller than this
    private static final int SINGLE_THREAD_THRESHOLD = 1000;

    public SortThread(int[] arr, int start, int end) {
        this.arr = arr;
        this.start = start;
        this.end = end;
    }

    @Override
    public void run() {
        // Use single-threaded sort for small subarrays
        if (end - start < SINGLE_THREAD_THRESHOLD) {
            quickSortSingleThread(arr, start, end);
            return;
        }

        if (start < end) {
            int partitionIndex = partition(arr, start, end);
            SortThread sortThreadLeft = new SortThread(arr, start, partitionIndex - 1);
            SortThread sortThreadRight = new SortThread(arr, partitionIndex + 1, end);
            Thread sortLeft = new Thread(sortThreadLeft);
            Thread sortRight = new Thread(sortThreadRight);
            
            sortLeft.start();
            sortRight.start();
            
            // Wait for child threads to finish before exiting this thread
            try {
                sortLeft.join();
                sortRight.join();
            } catch (InterruptedException e) {
                // Restore interrupt status if interrupted
                Thread.currentThread().interrupt();
            }
        }
    }

    // Single-threaded quicksort for small arrays
    private void quickSortSingleThread(int[] arr, int start, int end) {
        if (start < end) {
            int partitionIndex = partition(arr, start, end);
            quickSortSingleThread(arr, start, partitionIndex - 1);
            quickSortSingleThread(arr, partitionIndex + 1, end);
        }
    }

    private int partition(int arr[], int begin, int end) {
        int pivot = arr[end];
        int i = (begin - 1);
        for (int j = begin; j < end; j++) {
            if (arr[j] <= pivot) {
                i++;
                int swpTemp = arr[i];
                arr[i] = arr[j];
                arr[j] = swpTemp;
            }
        }
        int swapTemp = arr[i + 1];
        arr[i + 1] = arr[end];
        arr[end] = swapTemp;
        return i + 1;
    }
}

Then, Update the Main Class

Wait for the main sort thread to finish so you know when sorting is done:

import java.util.Random;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        int[] arr;
        Random random = new Random();
        arr = new int[53000000];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = random.nextInt();
        }
        
        SortThread sortThread = new SortThread(arr, 0, arr.length - 1);
        Thread threadSort = new Thread(sortThread);
        threadSort.start();
        
        // Wait for the main sort thread to complete
        threadSort.join();
        System.out.println("Sorting finished successfully!");
    }
}

Even Better: Use a Thread Pool

For more control over thread count (matching your CPU core count), replace manual thread creation with an ExecutorService:

// Update SortThread to accept an ExecutorService
public class SortThread implements Runnable {
    private int[] arr;
    private int start;
    private int end;
    private ExecutorService executor;
    private static final int SINGLE_THREAD_THRESHOLD = 1000;

    public SortThread(int[] arr, int start, int end, ExecutorService executor) {
        this.arr = arr;
        this.start = start;
        this.end = end;
        this.executor = executor;
    }

    @Override
    public void run() {
        if (end - start < SINGLE_THREAD_THRESHOLD) {
            quickSortSingleThread(arr, start, end);
            return;
        }

        if (start < end) {
            int partitionIndex = partition(arr, start, end);
            // Submit child tasks to the thread pool
            executor.submit(new SortThread(arr, start, partitionIndex - 1, executor));
            executor.submit(new SortThread(arr, partitionIndex + 1, end, executor));
        }
    }

    // quickSortSingleThread and partition methods remain the same...
}

And update Main to use the thread pool:

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        int[] arr;
        Random random = new Random();
        arr = new int[53000000];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = random.nextInt();
        }
        
        // Create a thread pool with size matching your CPU core count
        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        executor.submit(new SortThread(arr, 0, arr.length - 1, executor));
        
        // Shutdown the pool and wait for all tasks to finish
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.HOURS); // Adjust timeout as needed
        System.out.println("Sorting finished successfully!");
    }
}

Why This Works

  • Threshold for single-threaded sorting: Avoids thread overhead for small arrays where it doesn't make sense.
  • Waiting for child threads: Prevents spawning thousands of threads at once, keeping the thread count manageable.
  • Thread pool: Limits threads to your CPU core count, so each core has exactly one thread to work on—no wasted context switching, and your CPU will hit near 100% utilization.

内容的提问来源于stack exchange,提问作者Farrukh Nabiyev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:28:03