文件目录遍历的并发算法
問題:算出指定目錄下文件的大小.
這個是個很簡單的問題嘛,直接做個遞歸就行,上順序算法:
public long getFileSize(final File file){if(file.isFile()){return file.length();}else{long total = 0;File files[] = file.listFiles();if(files == null)return 0;for(File f: files){total += getFileSize(f);}return total;}}很簡單,一個遞歸實現,那么現在我們思考并發的算法
并發思路:每次進行遞歸運算,每次開一個線程去計算當前目錄的文件大小,然后進行遞歸運算
并發代碼:
private long getFileSizebf(final ExecutorService service,final File file) throws InterruptedException, ExecutionException, TimeoutException{if(file.isFile())return file.length();else{final File files[] = file.listFiles();if(files == null)return 0;else{long total = 0;final List<Future<Long>> tasks = new ArrayList<Future<Long>>();for(final File f : files){tasks.add(service.submit(new Callable<Long>() {@Overridepublic Long call() throws Exception {// TODO Auto-generated method stub//進行遞歸,把子目錄的文件大小返回
return getFileSizebf(service, f);}}));}for(final Future<Long> fl : tasks){total += fl.get();}return total;}}}
看上去沒什么問題,我們來實際測試下;
我們看到,調用get從Future中取數據的時候,并沒有設置超時,實際運行中發現,當文件夾的目錄結構簡單,目錄樹比較淺的時候能夠跑出來,但是目錄樹結構復雜了以后,跑了很久還是跑不出來結果.
分析:我們每個線程會開啟新的線程去計算子目錄的大小,這個時候,線程會進入等待,等待子線程的返回結果,這個時候就會出現一種情況,假如目錄樹的結構復雜,那么很多線程會進入等待狀態,等待子線程的返回值,但是這些父線程還是占用著線程池,但是子線程請求不到線程池去執行,這個時候就會進入死鎖.
如下圖:
優化策略:1.既然是線程池的poolsize不夠用了,那么我們就增加poolsize的大小嘛,好了,現在我們面對的是一個目錄結構不那么復雜的,通過簡單地增加poolsize還可以做到,但是非常復雜的話就沒辦法了.
2.我們之所以會造成死鎖,是因為線程在占用線程池的情況下同時在等待子線程的返回結果,
優化版本1:
public class FileOPBX1 implements FileOpI {@Overridepublic long getTotalSizeOfFilesInDir(File f) {long total = 0;final ExecutorService eService = Executors.newFixedThreadPool(100);// TODO Auto-generated method stubfinal List<File> dirs = new ArrayList<>();dirs.add(f);//初始化當前文件夾while (!dirs.isEmpty()) {//每次計算dir里面一集目錄下的文件大小以及子目錄final List<Future<SubDirAndSize>> part = new ArrayList<>();for (final File dir : dirs) {part.add(eService.submit(new Callable<SubDirAndSize>() {@Overridepublic SubDirAndSize call() throws Exception {// TODO Auto-generated method stubreturn getEveryDir(dir);}}));}dirs.clear();//目錄分配任務完畢,清除//從返回的結果計算文件大小,并且把新的子目錄添加到待計算文件夾for (final Future<SubDirAndSize> subdir : part) {try {final SubDirAndSize sas = subdir.get();total += sas.size;dirs.addAll(sas.subDirs);} catch (InterruptedException | ExecutionException e) {// TODO Auto-generated catch block e.printStackTrace();}}System.out.println(dirs);}return total;}//計算當前一級目錄下文件的大小以及子目錄private SubDirAndSize getEveryDir(final File f) {long total = 0;final List<File> subDirs = new LinkedList<File>();if (f.isDirectory()) {final File[] sub = f.listFiles();if (sub != null) {for (final File dir : sub) {if (dir.isFile())total += dir.length();else {subDirs.add(dir);}}}}return new SubDirAndSize(total, subDirs);}public class SubDirAndSize {final public long size;final public List<File> subDirs;public SubDirAndSize(final long totalsize, final List<File> thesubDir) {size = totalsize;subDirs = Collections.unmodifiableList(thesubDir);}}}這個時候我們看結果:
運行花費時間9688
串行執行結果:19563974028
運行花費時間3230
并行執行結果:19563974028
?
轉載于:https://www.cnblogs.com/color-my-life/p/4352551.html
總結
以上是生活随笔為你收集整理的文件目录遍历的并发算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机科学导论学习资料
- 下一篇: JS移动客户端--触屏滑动事件 ban