对“睡眠排序法”的改进,涉及到并发编程相关的内容哦
看到了这么一个排序方法,很有趣,基本思想是:
根据CPU的调度算法实现的,对一组数据进行排序,不能存在负数值,这个数是多大,那么就在线程里睡眠它的 10 倍再加 10,不是睡眠和它的数值一样大的原因是,当数值太小时,误差太大,睡眠的时间不比输出的时间少,那么就会存在不正确的输出结果。
一个偶然的机会在某个群内讨论到 CompletionService,于是突发奇想用它来实现一下
public class SleepSort {
public static void main(String[] args) {
// 初始数组
int[] arr = {1, 4, 7, 3, 8, 0, 9, 2, 6, 5, 0};
// 排序基本属于计算密集型,所以考虑池内线程数为 CPU 个数
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// 这个小工具属于并发编程里非常牛叉的一个,能根据任务完成快慢,优先拿到最先完成的任务
CompletionService<Integer> service = new ExecutorCompletionService<>(executor);
for (int value : arr) {
// 提交任务到线程池中,如果待排序数据量比较小的话,基本可以认为线程们同时在执行
service.submit(new Sorter(value));
}
// 排序结果
int len = arr.length;
int[] sort = new int[len];
for (int i = 0; i < len; i++) {
try {
// 谁先完成就先拿到谁,所以排序的结果就在这里出来了
// 相同值不能保证先后顺序,比如两个 0 的时候,只能依次取出
Future<Integer> take = service.take();
sort[i] = take.get();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("sort complete: " + Arrays.toString(sort));
// 关闭线程池
executor.shutdown();
}
/**
* 由于要拿到结果,所以需要实现 Callable 接口
*/
private static class Sorter implements Callable<Integer> {
private final int value;
public Sorter(int value) {
this.value = value;
}
@Override
public Integer call() throws Exception {
// 这里即是睡眠排序算法的核心思想
// x10 是为了能够完整的体现排序结果的精度,不乘以 10 的话,有一定几率达不到预期的排序效果
Thread.sleep(value * 10);
// 原值不动的时候
//Thread.sleep(value);
return value;
}
}
}
执行结果:
睡眠事件 x10 :
sort complete: [0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
原值进行睡眠,有可能排序不正确:
sort complete: [0, 0, 2, 1, 3, 4, 5, 6, 7, 8, 9]
哈哈哈哈