文件目錄遍歷的併發算法

問題:算出指定目錄下文件的大小.算法

這個是個很簡單的問題嘛,直接作個遞歸就行,上順序算法:多線程

    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;
        }
    }

很簡單,一個遞歸實現,那麼如今咱們思考併發的算法併發

併發思路:每次進行遞歸運算,每次開一個線程去計算當前目錄的文件大小,而後進行遞歸運算ide

併發代碼:測試

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>() {

                        @Override
                        public 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中取數據的時候,並無設置超時,實際運行中發現,當文件夾的目錄結構簡單,目錄樹比較淺的時候可以跑出來,可是目錄樹結構複雜了之後,跑了好久仍是跑不出來結果.spa

分析:咱們每一個線程會開啓新的線程去計算子目錄的大小,這個時候,線程會進入等待,等待子線程的返回結果,這個時候就會出現一種狀況,假如目錄樹的結構複雜,那麼不少線程會進入等待狀態,等待子線程的返回值,可是這些父線程仍是佔用着線程池,可是子線程請求不到線程池去執行,這個時候就會進入死鎖.線程

以下圖:code

優化策略:1.既然是線程池的poolsize不夠用了,那麼咱們就增長poolsize的大小嘛,好了,如今咱們面對的是一個目錄結構不那麼複雜的,經過簡單地增長poolsize還能夠作到,可是很是複雜的話就沒辦法了.blog

2.咱們之因此會形成死鎖,是由於線程在佔用線程池的狀況下同時在等待子線程的返回結果,

優化版本1:

public class FileOPBX1 implements FileOpI {

    @Override
    public long getTotalSizeOfFilesInDir(File f) {

        long total = 0;
        final ExecutorService eService = Executors.newFixedThreadPool(100);
        // TODO Auto-generated method stub
        final 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>() {

                    @Override
                    public SubDirAndSize call() throws Exception {
                        // TODO Auto-generated method stub
                        return 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

相關文章
相關標籤/搜索