• Java实现“睡排序”——线程池Executors的使用


    前提

    之前在知乎上看见一个有意思的排序算法——睡排序。

    睡排序最早好像是4chan上一个用户用shell脚本实现的:

    算法思想简洁明了:利用进程的sleep来实现 越大的数字越迟输出。

    虽然像2L说的那样,这个算法没什么利用价值。但我打算试着用Java来实现一下这个“睡排序”。

    Java实现

    既然选择用Java来实现,我们就没必要为数组中每一个元素启一个进程,启多线程就够了。

    Java启线程的方式有很多:1.继承Thread 2.实现Runnable 3.实现Callable ...

    而当前需求是要同时启固定数量的多个线程,那么通过Executor提供的线程池来启线程最合适不过了。

    下面是代码:

        public static List<Integer> sleepSort(int[] nums){
            List<Integer> res = new Vector<>();  // 1
            ExecutorService executor = Executors.newFixedThreadPool(nums.length);
            IntStream.of(nums).forEach(i -> executor.execute(() -> {
                try {
                    Thread.sleep(i * 200);  // 2
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                res.add(i);
            }));
            executor.shutdown();
            while (true){  // 3
                if (executor.isTerminated())
                    break;
            }
            return res;
        }

    几个注意点:

    1. 作为一个排序方法只是打印结果的话未免有些单调,所以我打算返回一个List作为排序后的结果。因为涉及多线程的操作,这里选择线程安全的Vector。

    2. forEach的遍历方式会使各个线程的启动时间有细微的差距,因此sleep的时间不能太多。经过测试,* 200(ms) 比较合适。

    3. 在返回结果之前,必须保证所有线程执行完毕。注意 "executor.shutdown()" 只是关闭线程池,并不会终止线程。所以要通过 "executor.isTerminated()" 来判断。

    算法分析
    这个算法看起来的复杂度是O(nums.length)。 实际上,复杂度为O(n ^ 2 ),因为维护多个后台线程程依赖于CPU来管理进程的上下文切换和优先级,所以该算法基本上将实际排序外包给了CPU。

    测试

    写一个生成乱序数组的方法,用于生成测试用例。

        public static int[] getRandomArray(int len, int maxNum){
            int[] res = new int[len];
            Random random = new Random();
            for (int i=0;i<len;i++) {
                res[i] = random.nextInt(maxNum);
            }
            return res;
        }
    
        public static void main(String[] args){
            System.out.println(sleepSort(getRandomArray(18, 29)));
        }

    结果:

    理论上数组的最大长度为当前JVM能创建的最大线程数:(系统CPU内存- JVM内存- 系统预留内存) / (线程栈的大小)

    最后

    该算法仅供娱乐,如何什么可以改进的地方,欢迎讨论。

  • 相关阅读:
    iosopendev配置
    按Home键切换到后台后会触发libGPUSupportMercury.dylib: gpus_ReturnNotPermittedKillClient导致crash
    iphone图片简单处理
    iPhone开发小工具
    iphone开发设置默认字体
    NSString+TimeCategory
    UIButton zoomin pressed
    Centos7下卸载docker
    如何清理Docker占用的磁盘空间
    美国VPS推荐1GB 50GB可以win
  • 原文地址:https://www.cnblogs.com/yucfeng/p/9204677.html
Copyright © 2020-2023  润新知