我编写了使用多线程计算给定数组中最小和最大数的代码。这个想法类似于binarysearch
,我只是将数组分成两半并计算每一半的最小值和最大值,并相应地更新我的最小和最大字段。
这可能是用于多线程的愚蠢示例。但既然我想到了这一点,我想实现并看看它是如何发展的。到目前为止,代码SURPRISINGLY工作正确。我希望它不能给出正确的结果,因为我不是在等待第一个线程完成,而是立即关闭第二个线程。这意味着最小值和最大值不得正确更新。
有人可以指出为什么这在多次运行和任何改进空间都能正常工作。
代码在这里
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class MinMax implements Runnable{
Long min=Long.MAX_VALUE;
Long max=Long.MIN_VALUE;
int low;
int high;
Long[] arr;
public MinMax(int low, int high, Long[] arr){
this.low = low;
this.high=high;
this.arr = arr;
}
@Override
public void run() {
System.out.println("called run ");
if (low-high<=2){
System.out.println("called ");
List<Long> l = Arrays.asList(arr);
min=Collections.min(l) < min ? Collections.min(l) : min;
max=Collections.max(l) > max ? Collections.max(l) : max;
}
else {
System.out.println(Thread.currentThread());
int mid = (high+low)/2;
MinMax left = new MinMax(low,mid,arr);
MinMax right = new MinMax(mid,high,arr);
Thread t1 = new Thread(left);
Thread t2 = new Thread(right);
t1.start();
t2.start();
Set<Thread> threadset=Thread.getAllStackTraces().keySet();
for (Thread t : threadset)
System.out.println(t.getName());
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args){
long[] arr = {3,4,5,1123,567,78,90,5,35434,1,34,56,111,2,56,789,87645,343535};
Long[] newarr= new Long[arr.length];
int i = 0;
for (long temp : arr)
newarr[i++]=temp;
MinMax m = new MinMax(0,arr.length,newarr);
m.run();
System.out.println(m.min);
System.out.println(m.max);
}
}
答案 0 :(得分:3)
为什么会这样?第一次low
0
和high
约为18
。 low-high<=2
为真,您的线程代码未被调用。无论如何,线程代码都不会产生任何结果。
ForkJoinPool
旨在为您处理这类事情。
答案 1 :(得分:1)
我对您的代码的评论 - 首先,min
和max
需要声明为volatile
,以确保它们的值在线程内及时更新。
然后,这个比较不是原子的,您可能需要将其包装到synchronized
块中,或者如果AtomicInteger
性能是compareAndSet
,则可以考虑synchronized
的{{1}} optmization不满意:
min=Collections.min(l) < min ? Collections.min(l) : min;
max=Collections.max(l) > max ? Collections.max(l) : max;
所以问题可能是两个线程同时计算它们的最小值,但是它们在不同的时间分配它,所以获胜者是谁的结果首先被写入。
正如@JamesKingsbery注意到你可能需要在第二个帖子上调用start()
。
可能是最后一件事,你可能不会在你的情况下获得任何性能提升,但这是一个很好的学习例子。
答案 2 :(得分:0)
为此使用RecursiveAction
类。在这里,我使用RecursiveAction
编写了程序。请找到以下代码。有关详细信息,请查看http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/RecursiveAction.html
package org.kavi.threadexample;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
public class MinMax extends RecursiveAction{
Long min=Long.MAX_VALUE;
Long max=Long.MIN_VALUE;
int low;
int high;
Long[] arr;
public MinMax(int low, int high, Long[] arr){
this.low = low;
this.high=high;
this.arr = arr;
}
@Override
protected void compute() {
if (low-high<=2){
System.out.println("called ");
List<Long> l = Arrays.asList(arr);
min=Collections.min(l) < min ? Collections.min(l) : min;
max=Collections.max(l) > max ? Collections.max(l) : max;
}
else {
int mid = (low + high) >>> 1;
MinMax left = new MinMax(low, mid,arr );
MinMax right = new MinMax(mid, high, arr);
}
}
public static void main(String[] args){
long[] arr = {3,4,5,1123,567,78,90,5,35434,1,34,56,111,2,56,789,87645,343535};
Long[] newarr= new Long[arr.length];
int i = 0;
for (long temp : arr) {
newarr[i++]=temp;
}
MinMax m = new MinMax(0,arr.length,newarr);
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(m);
System.out.println(m.min);
System.out.println(m.max);
}
}
答案 3 :(得分:0)
@KaviK RecursiveAction示例的固定版本:
(KaviK版本中的错误包括未实际调用递归任务,未合并其结果以及一次计算整个集合的最小值/最大值,而不是进行任何实际尝试来细分任务)
#!/usr/bin/env bash
WORK_DIR=~/work_dir/
FOLDERS_TO_SEARCH=$(find $WORK_DIR -maxdepth 1 -type d)
count=0
for i in $FOLDERS_TO_SEARCH
do
count=$(($count+1))
if [[ $count -eq 1 ]];then
echo "Skipping root directory: $i"
else
find $i -maxdepth 1 -type f
fi
done