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内存- 系统预留内存) / (线程栈的大小)
最后
该算法仅供娱乐,如何什么可以改进的地方,欢迎讨论。
Java实现“睡排序”——线程池Executors的使用的更多相关文章
- 深入理解Java自带的线程池和缓冲队列
前言 线程池是什么 线程池的概念是初始化线程池时在池中创建空闲的线程,一但有工作任务,可直接使用线程池中的线程进行执行工作任务,任务执行完成后又返回线程池中成为空闲线程.使用线程池可以减少线程的创建和 ...
- 【转】线程池体系介绍及从阿里Java开发手册学习线程池的正确创建方法
jdk1.7中java.util.concurrent.Executor线程池体系介绍 java.util.concurrent.Executor : 负责线程的使用与调度的根接口 |–Execut ...
- java多线程9:线程池
线程池 线程池的优点 我们知道线程的创建和上下文的切换也是需要消耗CPU资源的,所以在多线程任务下,使用线程池的优点就有: 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. ...
- Java并发编程:线程池的使用
Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...
- Java多线程系列--“JUC线程池”06之 Callable和Future
概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...
- Java多线程系列--“JUC线程池”03之 线程池原理(二)
概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...
- JAVA基础拾遗-论线程池的线程粒度划分与深浅放置
摘要:多线程任务处理对提高性能很有帮助,在Java中提供的线程池也方便了对多线程任务的实现.使用它很简单,而如果进行了不正确的使用,那么代码将陷入一团乱麻.因此如何正确地使用它,如以下分享,这个技能你 ...
- Java并发编程:线程池的使用(转)
Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...
- Java视频扩展知识 线程池的了解
Java视频扩展知识 线程池的了解 1.简单介绍: Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的 ...
随机推荐
- Codeforces(Round #93) 126 B. Password
B. Password time limit per test 2 seconds memory limit per test 256 megabytes Asterix, Obelix an ...
- 22_CopyOnWrite容器
[简述] Copy-On-Write简称COW,是一种程序设计中的优化策略. JDK里的COW容器分为两种:CopyOnWriteArrayList 和 CopyOnWriteArraySet. Co ...
- 提问的智慧 How To Ask Questions The Smart Way
提问的智慧 How To Ask Questions The Smart Way Copyright © 2001,2006,2014 Eric S. Raymond, Rick Moen 本指南英文 ...
- [转] RISC-V架构介绍
1. RISC-V和其他开放架构有何不同 如果仅从"免费"或"开放"这两点来评判,RISC-V架构并不是第一个做到免费或开放的处理器架构. 在开始之前,我们先通 ...
- csdn中使用Git的一些注意问题
1.生成的密钥必须在当前用户文档目录下的.ssh文件夹.----否则不行 2.生成的密钥文件命名---必须命名为id_ras文件----否则不行
- SQL Server ->> 内置标量函数TRY_PARSE、TRY_CAST和TRY_CONVERT的各自特点和区别
SQL Server到了目前的2014版本有三个函数是用来转换数据格式的.虽说之前版本中已经有CAST和CONVERT这两个函数来干这个事情.问题是,一旦往目标数据类型转换失败就会造成报错. TRY_ ...
- 鲁棒图(Robustness Diagram)
鲁棒图与系统需求分析 鲁棒图(Robustness Diagram)是由Ivar Jacobson于1991年发明的,用以回答“每个用例需要哪些对象”的问题.后来的UML并没有将鲁棒图列入UML标准, ...
- React Native调试技巧与心得
转自:http://blog.csdn.net/quanqinyang/article/details/52215652 在做React Native开发时,少不了的需要对React Native程序 ...
- batik-all-1.7
处理highcharts导出图片出现中文乱码所用到的jar包
- HandyJSON代码阅读
功能:model = modelType.transform(rawdata) 使用分析: 使用机制:继承+实现配置+使用: 需要自己实现什么? 设计分析: 工具模块?机制模块?model基类? 生成 ...