給定根目錄,遞歸累加所有常規文件大小。IO 密集型任務,順序遞歸受限於單線程磁盤調度,並行化可顯著提升吞吐(特別是 SSD/RAID/網絡存儲)。
public class SequentialSize {
public long calculate(File root) {
if (root.isFile()) return root.length();
long total = 0;
File[] children = root.listFiles();
if (children != null) {
for (File child : children) {
total += calculate(child);
}
}
return total;
}
}
特點:代碼最簡潔,棧深度受限於目錄層級,大目錄棧溢出風險,無法利用多核。
public class FixedPoolBatch {
private final ExecutorService pool = Executors.newFixedThreadPool(100);
public long calculate(File root) throws InterruptedException, ExecutionException {
long total = 0;
List dirs = new ArrayList<>();
dirs.add(root);
while (!dirs.isEmpty()) {
List> futures = new ArrayList<>();
// 提交當前層級所有目錄任務
for (File dir : dirs) {
futures.add(pool.submit(() -> scanDir(dir)));
}
dirs.clear();
// 收集結果,發現子目錄加入下輪
for (Future f : futures) {
DirResult r = (DirResult) f.get(); // 需自定義結果類攜帶子目錄列表
total += r.size;
dirs.addAll(r.subDirs);
}
}
return total;
}
private DirResult scanDir(File dir) { /* 返回 size + subDirs */ }
}
缺陷:層級同步屏障,淺層目錄並行度低,深層目錄任務堆積,Future.get() 串行等待。
public class NaiveRecursiveSubmit {
private long calculate(ExecutorService pool, File file) throws Exception {
if (file.isFile()) return file.length();
List> futures = new ArrayList<>();
for (File child : file.listFiles()) {
futures.add(pool.submit(() -> calculate(pool, child))); // 遞歸提交
}
return futures.stream().mapToLong(f -> f.get()).sum();
}
}
嚴重問題:文件數 = 任務數,百萬文件創建百萬任務,線程池隊列 OOM,上下文切換開銷巨大。
public class LatchAtomic {
private final ExecutorService pool = Executors.newFixedThreadPool(100);
private final AtomicLong pending = new AtomicLong(1); // 根任務
private final AtomicLong total = new AtomicLong();
private final CountDownLatch latch = new CountDownLatch(1);
public long calculate(File root) throws InterruptedException {
pool.execute(() -> scan(root));
latch.await(100, TimeUnit.SECONDS);
return total.get();
}
private void scan(File file) {
long size = 0;
if (file.isDirectory()) {
for (File child : file.listFiles()) {
if (child.isDirectory()) {
pending.incrementAndGet();
pool.execute(() -> scan(child)); // 異步提交子目錄
} else {
size += child.length();
}
}
} else {
size = file.length();
}
total.addAndGet(size);
if (pending.decrementAndGet() == 0) latch.countDown();
}
}
優勢:無層級屏障,動態任務提交,原子計數器精確協調完成時刻。
public class QueueBased {
private final ExecutorService pool = Executors.newFixedThreadPool(100);
private final BlockingQueue sizeQueue = new ArrayBlockingQueue<>(500);
private final AtomicLong pending = new AtomicLong();
public long calculate(File root) throws InterruptedException {
pending.incrementAndGet();
pool.execute(() -> scan(root));
long total = 0;
while (pending.get() > 0 || !sizeQueue.isEmpty()) {
Long size = sizeQueue.poll(10, TimeUnit.SECONDS);
if (size != null) total += size;
}
return total;
}
private void scan(File file) {
long size = 0;
if (file.isDirectory()) {
for (File child : file.listFiles()) {
if (child.isDirectory()) {
pending.incrementAndGet();
pool.execute(() -> scan(child));
} else {
size += child.length();
}
}
} else {
size = file.length();
}
sizeQueue.offer(size); // 隔離結果收集
pending.decrementAndGet();
}
}
特點:結果通過隊列傳遞,解耦計算與聚合,隊列容量可背壓防 OOM。
public class ForkJoinSize {
private static final ForkJoinPool POOL = new ForkJoinPool();
public long calculate(File root) {
return POOL.invoke(new SizeTask(root));
}
private static class SizeTask extends RecursiveTask {
private final File file;
SizeTask(File file) { this.file = file; }
@Override
protected Long compute() {
if (file.isFile()) return file.length();
long size = 0;
List tasks = new ArrayList<>();
for (File child : file.listFiles()) {
if (child.isFile()) {
size += child.length();
} else {
tasks.add(new SizeTask(child));
}
}
// 批量 fork 子任務
invokeAll(tasks);
// join 收集結果
for (SizeTask t : tasks) size += t.join();
return size;
}
}
}
核心優勢:
| 方案 | 預期耗時 | CPU 利用率 | 代碼複雜度 | 推薦指數 |
|---|---|---|---|---|
| 單線程遞歸 | 基準 1.0x | ~12% | ⭐ | ⭐⭐ |
| FixedPool 批次 | 0.6x | ~45% | ⭐⭐⭐ | ⭐⭐ |
| CountDownLatch | 0.4x | ~70% | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| BlockingQueue | 0.4x | ~70% | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| ForkJoinPool | 0.35x | ~85% | ⭐⭐ | ⭐⭐⭐⭐⭐ |