【发布时间】:2014-09-04 12:23:03
【问题描述】:
为了简化我的例子,假设我正在使用 Java 的 Fork-Join 框架实现二进制搜索。我的目标是在整数数组中找到一个特定的整数值(目标整数)。这可以通过将数组分成两半来完成,直到它小到可以执行串行搜索。算法的结果需要是一个布尔值,表示是否在数组中找到目标整数。
在幻灯片 28 之后的Klaus Kreft's presentation 中探讨了类似的问题。然而,Kreft 的目标是找到数组中的最大数,因此必须扫描所有条目。就我而言,没有必要扫描整个数组,因为一旦找到目标整数,就可以停止搜索。
我的问题是,一旦我遇到目标整数,许多任务已经被插入到线程池中,我需要取消它们,因为继续搜索没有意义。我尝试从 RecursiveTask 内部调用 getPool().terminate() 但这并没有太大帮助,因为许多任务已经排队,我什至注意到即使在调用 shutdown 之后新的一次也排队..
我当前的解决方案是使用一个静态的 volatile 布尔值,该布尔值初始化为“false”,并在任务开始时检查其值。如果仍然为“假”,则任务开始工作,如果为“真”,则任务立即返回。我实际上可以为此使用 RecursiveAction。
所以我认为这个解决方案应该可以工作,但我想知道框架是否提供了一些处理此类情况的标准方法 - 即为递归定义一个停止条件,从而取消所有排队的任务。
请注意,如果我想在找到目标整数时立即停止所有正在运行的任务(通过其中一个正在运行的任务),我必须检查这些任务中每一行之后的布尔值,这可能会影响性能,因为它的值boolean 不能被缓存(它被定义为 volatile)。
确实,我认为需要一些标准解决方案,并且可以以清除队列和中断正在运行的任务的形式提供。但是我还没有找到这样的解决方案,我想知道是否有其他人知道它或有更好的想法。
感谢您的宝贵时间, 阿萨夫
编辑:这是我的测试代码:
package xxx;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
public class ForkJoinTest {
static final int ARRAY_SIZE = 1000;
static final int THRESHOLD = 10;
static final int MIN_VALUE = 0;
static final int MAX_VALUE = 100;
static Random rand = new Random();
// a function for retrieving a random int in a specific range
public static int randInt(int min, int max) {
return rand.nextInt((max - min) + 1) + min;
}
static volatile boolean result = false;
static int[] array = new int[ARRAY_SIZE];
static int target;
@SuppressWarnings("serial")
static class MyAction extends RecursiveAction {
int startIndex, endIndex;
public MyAction(int startIndex, int endIndex) {
this.startIndex = startIndex;
this.endIndex = endIndex;
}
// if the target integer was not found yet: we first check whether
// the entries to search are too few. In that case, we perform a
// sequential search and update the result if the target was found.
// Otherwise, we break the search into two parts and invoke the
// search in these two tasks.
@Override
protected void compute() {
if (!result) {
if (endIndex-startIndex<THRESHOLD) {
//
for (int i=startIndex ; i<endIndex ; i++) {
if (array[i]==target) {
result = true;
}
}
} else {
int middleIndex = (startIndex + endIndex) / 2;
RecursiveAction action1 = new MyAction(startIndex, middleIndex);
RecursiveAction action2 = new MyAction(middleIndex+1, endIndex);
invokeAll(Arrays.asList(action1,action2));
}
}
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
for (int i=0 ; i<ARRAY_SIZE ; i++) {
array[i] = randInt(MIN_VALUE, MAX_VALUE);
}
target = randInt(MIN_VALUE, MAX_VALUE);
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(new MyAction(0,ARRAY_SIZE));
System.out.println(result);
}
}
【问题讨论】:
-
你能发布一些代码吗?您可以使用可以清除的特定队列,也可以中断正在运行的线程,但查看代码更容易为您提供正确的建议。
-
我维护了一个开源的 fork/join 框架,它提供了一个并行顺序搜索来处理您对“查找优先”的需求。您可以按原样使用它,也可以使用代码作为示例来说明如何操作它自己。 sourceForge 链接为:sourceforge.net/projects/tymeacdse/?source=navbar
-
谢谢@edharned,我去看看。它是否依赖于 Java 的 fork/join 框架?您是否还使用 volatile boolean / AtomicBoolean 来停止搜索?
-
@Assaf 不,它不使用 Java F/J 框架。它正确地执行 F/J。顺序并行搜索是 17 个内置函数之一。一旦找到“首先找到”,它就会使用 volatile 布尔值来停止其他线程。还有find-any、find-last、find-all。