모든 병렬 계산이 완료되었지만 '기본'스레드가 다른 작업과 함께 계속되는 경우가 종종 멈추는 동시 재귀 적 디렉터리 통과 및 파일 처리 프로그램을 만들었습니다.동시 디렉토리 탐색 알고리즘 정지 문제
코드는 기본적으로 포크 - 조인 스타일 동시 집계이고 병렬 집계가 완료된 후에는 결과를 스윙 창에 표시해야합니다. 집계의 문제점은 트리를 생성하고 계층 구조에서 리프 노드의 통계를 집계해야한다는 것입니다.
동시성 실수가 있었지만 찾을 수 없다고 확신합니다. 나는 포스트의 마지막 부분에 코드의 관련 부분을 포함시켰다. (간략하게하기 위해 코드 주석을 제거했다. 150 줄을 유감스럽게 생각한다. 필요하다면, 그것을 외부 위치로 옮길 수있다.)
컨텍스트 : Java 6u13, Windows XP SP3, 코어 2 듀오 CPU.
내 질문은 :
는 이것이 임의 정지의 원인이 될 수 있을까?
아마도 기존 라이브러리의 형태로 동시 디렉토리 트래버 설을 수행하는 더 좋은 방법이 있습니까?
더그 레아 (또는 Java 7) 통합/디렉토리 탐색을위한 더 나은 프레임 워크에서 포크 - 조인 프레임 워크가 될 것인가, 그렇다면 어떻게 내 구현을 다시 생각한다 - 개념적 수준에서?
감사합니다.
그리고 코드 발췌 :
private static JavaFileEvaluator[] processFiles(File[] files)
throws InterruptedException {
CountUpDown count = new CountUpDown();
ThreadPoolExecutor ex = (ThreadPoolExecutor)Executors
.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
JavaFileEvaluator[] jfes = new JavaFileEvaluator[files.length];
for (int i = 0; i < jfes.length; i++) {
count.increment();
jfes[i] = new JavaFileEvaluator(files[i], count, ex);
ex.execute(jfes[i]);
}
count.await();
for (int i = 0; i < jfes.length; i++) {
count.increment();
final JavaFileEvaluator jfe = jfes[i];
ex.execute(new Runnable() {
public void run() {
jfe.aggregate();
}
});
}
// -------------------------------------
// this await sometimes fails to wake up
count.await(); // <---------------------
// -------------------------------------
ex.shutdown();
ex.awaitTermination(0, TimeUnit.MILLISECONDS);
return jfes;
}
public class JavaFileEvaluator implements Runnable {
private final File srcFile;
private final Counters counters = new Counters();
private final CountUpDown count;
private final ExecutorService service;
private List<JavaFileEvaluator> children;
public JavaFileEvaluator(File srcFile,
CountUpDown count, ExecutorService service) {
this.srcFile = srcFile;
this.count = count;
this.service = service;
}
public void run() {
try {
if (srcFile.isFile()) {
JavaSourceFactory jsf = new JavaSourceFactory();
JavaParser jp = new JavaParser(jsf);
try {
counters.add(Constants.FILE_SIZE, srcFile.length());
countLines();
jp.parse(srcFile);
Iterator<?> it = jsf.getJavaSources();
while (it.hasNext()) {
JavaSource js = (JavaSource)it.next();
js.toString();
processSource(js);
}
// Some catch clauses here
}
} else
if (srcFile.isDirectory()) {
processDirectory(srcFile);
}
} finally {
count.decrement();
}
}
public void processSource(JavaSource js) {
// process source, left out for brevity
}
public void processDirectory(File dir) {
File[] files = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return
(pathname.isDirectory() && !pathname.getName().startsWith("CVS")
&& !pathname.getName().startsWith("."))
|| (pathname.isFile() && pathname.getName().endsWith(".java")
&& pathname.canRead());
}
});
if (files != null) {
Arrays.sort(files, new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
if (o1.isDirectory() && o2.isFile()) {
return -1;
} else
if (o1.isFile() && o2.isDirectory()) {
return 1;
}
return o1.getName().compareTo(o2.getName());
}
});
for (File f : files) {
if (f.isFile()) {
counters.add(Constants.FILE, 1);
} else {
counters.add(Constants.DIR, 1);
}
JavaFileEvaluator ev = new JavaFileEvaluator(f, count, service);
if (children == null) {
children = new ArrayList<JavaFileEvaluator>();
}
children.add(ev);
count.increment();
service.execute(ev);
}
}
}
public Counters getCounters() {
return counters;
}
public boolean hasChildren() {
return children != null && children.size() > 0;
}
public void aggregate() {
// recursively aggregate non-leaf nodes
if (!hasChildren()) {
count.decrement();
return;
}
for (final JavaFileEvaluator e : children) {
count.increment();
service.execute(new Runnable() {
@Override
public void run() {
e.aggregate();
}
});
}
count.decrement();
}
}
public class CountUpDown {
private final Lock lock = new ReentrantLock();
private final Condition cond = lock.newCondition();
private final AtomicInteger count = new AtomicInteger();
public void increment() {
count.incrementAndGet();
}
public void decrement() {
int value = count.decrementAndGet();
if (value == 0) {
lock.lock();
try {
cond.signalAll();
} finally {
lock.unlock();
}
} else
if (value < 0) {
throw new IllegalStateException("Counter < 0 :" + value);
}
}
public void await() throws InterruptedException {
lock.lock();
try {
if (count.get() > 0) {
cond.await();
}
} finally {
lock.unlock();
}
}
}
편집 추가 hasChildren() JavaSourceEvaluator의 방법.
와우, 네 말이 맞아! 누락 된 hasChildren을 추가했습니다. 시체를 try-finally로 포장하여 잠시 동안 루프에서 코드를 실행합니다. 감사합니다! +1. 당신은 또한 두 번째와 세 번째 질문에 반영 할 수 있을까요? – akarnokd
1 년 전에이 코드를 처음 시작했을 때 라이브러리를 찾지 못했습니다. 이런 종류의 병렬 트래버스는 fj 프레임 워크에 아웃소싱 된 것 같습니다. 고맙습니다. – akarnokd