前提

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

睡排序最早好像是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. c++中%是什么意思?

    两种意思:1.格式化字符串输出2.整数取余 1.目前printf支持以下格式的输出,例如:printf("%c",a):输出单个字符.printf("%d",a ...

  2. git internal for computer scientists

    http://eagain.net/articles/git-for-computer-scientists/ git object storage仅仅是一个DAG of objects, 有几种类型 ...

  3. SQL Server ->> Sparse File(稀疏文件)

    Sparse File(稀疏文件)不是SQL Server的特性.它属于Windows的NTFS文件系统的一个特性.如果某个大文件中的数据包含着大量“0数据”(这个应该从二进制上看),这样的文件就可以 ...

  4. 使用WdatePicker日期组件时,选择日期后,执行某个方法

    WdatePicker({onpicked:function(){alert(123);},dateFmt:'yyyy年MM月dd日',maxDate:'%y-%M-%d'}) 1.onpicked: ...

  5. 用WCAT进行IIS压力测试

    用WCAT进行IIS压力测试 分类: javascript专辑 IT信息化 2008-10-13 16:56 5754人阅读 评论(1) 收藏 举报 iis测试服务器microsoft脚本网络 如何建 ...

  6. error C2027: use of undefined type 'COleDispatchImpl'的解决方法

    解决办法:在资源管理视图中删除CMDTARG.CPP文件,然后重新编译 设置断点后,F5调试运行,调试运行后,然后关编辑器提示保存对CMDTARG.CPP的修改,点了保存,出现error C2027: ...

  7. Linux--sudo权限讲解

    sudo简介:sudo是linux系统管理指令,是允许系统管理员让普通用户执行一些或者全部的root命令的一个工具,如halt,reboot,su等等.这样不仅减少了root用户的登录 和管理时间,同 ...

  8. 第五周 day5 python学习笔记

    1.软件开发的常规目录结构 更加详细信息参考博客:http://www.cnblogs.com/alex3714/articles/5765046.html         2.python中的模块 ...

  9. Ubuntu 下安装apache+PHP

    1.安装apache2 sudo apt-get install apache2 运行如下命令重启:sudo /etc/init.d/apache2 restart 在浏览器里输入http://loc ...

  10. 获取DataTable某一列的所有值

    /// <summary> /// 获取某一列的所有值 /// </summary> /// <typeparam name="T">列数据类型 ...