【发布时间】:2014-07-17 21:16:01
【问题描述】:
我正在考虑使用一个易失数组来实现多线程排序。假设我有一个长度为 N 的数组和 M 个线程,它们将对数组的子范围进行排序。这些子范围是不相交的。然后,在主线程中,我将合并部分排序的数组。
示例代码:
final int N = ....
volatile MyClass[] array = new MyClass[N];
//... fill array with values
void sort(){
MyThread[] workers = new MyThread[M];
int len = N/M; //length of the sub-range
for(int i=0;i<M;++i){
workers[i] = new MyThread(i*len, (i+1)*len);
workers[i].start();
}
for(int i=0;i<M;++i)workers.join();
//now synchronization in memory using "happens before"
//will it work?
array = array;
//...merge sorted sub-ranges into one sorted array
}
private class MyThread extends Thread{
final int from;
final int to;
public MyThread(int from, int to){ ..... }
public void run(){
//...something like: quicksort(array, from, to);
//...without synchronization, ranges <from, to> are exclusive
}
我不需要在运行线程时在内存中进行同步,因为数组子范围是不相交的。我想在完成线程后进行一次同步。数组的更新版本(在主线程中看到)是否包含在工作线程中所做的所有更改?
如果这个方案有效,对大表有效吗?
提前感谢您的帮助。
编辑:
我进行了测试。无论使用 volatile 关键字,我都收到了正确的结果。但是 volatile 数组的执行时间要长几倍(大约 M 倍)。
【问题讨论】:
-
N 和 M 将有多大?你的目标系统可以本地运行多少线程?线程之间上下文切换的开销很可能会消耗多线程排序阶段的大部分加速。你会留下很多复杂的代码和(也许)小的性能提升。
-
N 大约是 10^6,M 是处理器核心数
-
在我的机器上用普通的
Collections.sort()对一百万个元素进行排序平均需要大约 400 毫秒的整数,650 毫秒的十六进制字符串。除非MyClass有一个超级复杂的比较逻辑,否则你会看到几秒钟,比如 -
为了简单起见,我写了关于排序的文章。工作线程在排序前还要进行其他操作,整个过程反复迭代(我的代码是遗传算法的实现)。
标签: java arrays multithreading sorting volatile