【问题标题】:Arrays sort method behavior数组排序方法行为
【发布时间】:2014-05-21 04:38:59
【问题描述】:

我正在阅读《真正不耐烦的 Java SE 8》一书,在第一章中我遇到了下一个练习题:

Arrays.sort 方法中的比较器代码是在与 sort 调用相同的线程中调用还是在不同的线程中调用?

我在 javadoc 中搜索了 Arrays.sort 重载,它采用 Comparator 参数,但没有指定任何关于线程的内容。 我假设出于性能原因,代码可以在另一个线程中执行,但这只是一个猜测。

【问题讨论】:

  • 它在同一个线程上调用。

标签: java arrays multithreading sorting


【解决方案1】:

您始终可以通过记录idThread.currentThread() 来测试它。

在调用 sort() 之前和您的 compare() 方法中添加一些内容。

logger.debug("Thread # " + Thread.currentThread().getId());

【讨论】:

    【解决方案2】:

    假设您有代码来获取数组中的最大元素:

    int[] array = new int[] {.........};
    /// Few/many lines of code between...
    Arrays.sort(array);
    int largest = array[array.length - 1];
    

    如果排序是在另一个线程中产生的,你会遇到一个竞争条件——你是先对数组排序,还是先分配largest?你可以通过锁定array 来避免这个问题,但是如果你运行的代码已经锁定array 会发生什么?您可以使用join() 阻止原始线程,但是您几乎无法实现生成另一个线程的目的,因为您的代码的行为方式与没有生成其他线程完全相同。

    对于Arrays#sort(),排序发生在原始线程中,因为生成另一个线程确实没有多大意义。您的线程将阻塞,直到排序完成,就像任何其他代码一样。

    最接近生成另一个线程进行排序的方法是 Java 8 中引入的 Arrays#parallelSort() 方法。这仍然与常规的 Arrays#sort() 几乎相同,因为它会阻塞当前线程直到排序完成,但是在后台产生了一些线程来帮助对数组进行排序。对于更大的数据集,我预计生成的线程数量会有所改善,减去可能存在的任何线程开销。

    【讨论】:

    • 线程将发生在sort 中。 sort 会在返回之前加入它创建的线程。
    • @SotiriosDelimanolis 但是对于sort(),如果您仍然要阻止原始线程,那么生成另一个线程有什么意义?
    • @SotiriosDelimanolis 哦等等,我明白你在说什么......让我编辑我的答案。
    【解决方案3】:

    在第一次测试中,代码将在单线程中运行。

    在第二个测试中,代码将在多个线程中运行。

    @Test
    public void shouldSortInSingleThread() {
    
        List<String> labels = new ArrayList<String>();
        IntStream.range(0, 50000).forEach(nbr -> labels.add("str" + nbr));
        System.out.println(Thread.currentThread());
        Arrays.sort(labels.toArray(new String[] {}), (String first,
                String second) -> {
            System.out.println(Thread.currentThread());
            return Integer.compare(first.length(), second.length());
    
        });
    
    }
    
    @Test
    public void shouldSortInParallel() {
    
        List<String> labels = new ArrayList<String>();
        IntStream.range(0, 50000).forEach(nbr -> labels.add("str" + nbr));
    
        System.out.println(Thread.currentThread());
        Arrays.parallelSort(labels.toArray(new String[] {}), (String first,
                String second) -> {
            System.out.println(Thread.currentThread());
            return Integer.compare(first.length(), second.length());
    
        });
    
    }
    

    【讨论】: