前提

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

睡排序最早好像是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的使用的更多相关文章

  1. 深入理解Java自带的线程池和缓冲队列

    前言 线程池是什么 线程池的概念是初始化线程池时在池中创建空闲的线程,一但有工作任务,可直接使用线程池中的线程进行执行工作任务,任务执行完成后又返回线程池中成为空闲线程.使用线程池可以减少线程的创建和 ...

  2. 【转】线程池体系介绍及从阿里Java开发手册学习线程池的正确创建方法

    jdk1.7中java.util.concurrent.Executor线程池体系介绍 java.util.concurrent.Executor : 负责线程的使用与调度的根接口  |–Execut ...

  3. java多线程9:线程池

    线程池 线程池的优点 我们知道线程的创建和上下文的切换也是需要消耗CPU资源的,所以在多线程任务下,使用线程池的优点就有: 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. ...

  4. Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  5. Java多线程系列--“JUC线程池”06之 Callable和Future

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

  6. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  7. JAVA基础拾遗-论线程池的线程粒度划分与深浅放置

    摘要:多线程任务处理对提高性能很有帮助,在Java中提供的线程池也方便了对多线程任务的实现.使用它很简单,而如果进行了不正确的使用,那么代码将陷入一团乱麻.因此如何正确地使用它,如以下分享,这个技能你 ...

  8. Java并发编程:线程池的使用(转)

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  9. Java视频扩展知识 线程池的了解

     Java视频扩展知识   线程池的了解 1.简单介绍: Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的 ...

随机推荐

  1. Ta们,用云计算改变着更多普通人的生活,所以,我们1218

    维族音乐的传承者:为家园建设生态农业:为50万货运司机谋福利:电视游戏行业复兴的倡导者:......还有很多平凡普通的人,不同的主角.不同的情节,用自己的云上轨迹在点滴改变着我们的周遭世界.所以,我们 ...

  2. TextSwitcher(文本切换器)和ViewFlipper

    1.TextSwitcher 使用: 应用分为三步: 1.得到 TextSwitcher 实例对象   TextSwitcher switcher = (TextSwitcher) findViewB ...

  3. c++ 判断是64还是32位系统

    1.IsWow64Process 确定指定进程是否运行在64位操作系统的32环境(Wow64)下. 语法 BOOL WINAPI IsWow64Process( __in HANDLE hProces ...

  4. 天诛进阶之D算法 #3700

    http://mp.weixin.qq.com/s/ngn98BxAOLxXPlLU8sWH_g 天诛进阶之D算法 #3700 2015-11-24 yevon_ou 水库论坛 天诛进阶之D算法 #3 ...

  5. mysql中replicate_wild_do_table和replicate_do_db区别

    使用replicate_do_db和replicate_ignore_db时有一个隐患,跨库更新时会出错. 如在Master(主)服务器上设置 replicate_do_db=test(my.conf ...

  6. CVE-2015-1642 POC

    月初,玄武实验室的“每日安全动态”推送了一篇office UAF漏洞利用的文章,之前对office上UAF漏洞利用占位问题有些疑问,刚好就借助这篇文章重现了一下.其中堆喷射部分不是特别稳定,漏洞成因和 ...

  7. Google Colab 免费的谷歌GPU for deep learning

    Who wants to use a free GPU for deep learning?Google Colab is a free cloud service and now it suppor ...

  8. 用phpstudy搭建的lnmp环境下mysql授权远程连接

    1.使用phpstudy安装的mysql没有放置到可以直接调用的目录里,所以只能使用绝对路径来访问: /phpstudy/mysql/bin/mysql -uroot -proot 2.执行use m ...

  9. 10个出色的NoSQL数据库(转)

    随着大数据的不断发展,非关系型的数据库现在成了一个极其热门的新领域,非关系数据库产品的发展非常迅速.现今的计算机体系结构在数据存储方面要有庞大的水平扩展性,而NoSQL也正是致力于改变这一现状.目前G ...

  10. UML用例图间关系说明

    用例间一般存在如下四种关系: 1."通信"关系(<<cmmunicate>>构造型): "通信"关系:使用实心的关联线或带<< ...