簡體   English   中英

Java中的Files.walkFileTree有沒有辦法暫停和恢復?

[英]Is there any way to pause and resume Files.walkFileTree in Java?

這個 class 走一條路徑,對於它命中的每個文件,它都會將一個線程扔到 ThreadPoolExecutor 中,該 ThreadPoolExecutor 將提供給它的對象收集到 HashMap 中。我有另一個線程監視 HashMap,當 Map 中有 5,000 個元素時,它被轉儲到 MySQL 數據庫,然后記錄的記錄從 HashMap 中清除,一切都像這樣繼續。

然而,一旦 walker 到達超過 200 萬個文件的位置,HashMap 的實際清除已經落后了將近一百萬個記錄,所以我希望能夠暫停文件夾的遍歷,直到數據轉儲被捕獲起來,然后繼續……沖洗重復……

這個 class 開始運行后是否可以暫停? 或者,有什么辦法可以減慢速度嗎?

public class WalkFilePaths implements Runnable{

    public WalkFilePaths(Path rootPath, ThreadPoolExecutor executor) {
        this.rootPath           = rootPath;
        this.executor           = executor;
    }

    private        final Path               rootPath;
    private static       ThreadPoolExecutor executor;
    private static final FileDataManager    fileDataManager = new FileDataManager();

    @Override public void run() {
        try {
            FolderWalker folderWalker = new FolderWalker();
            Files.walkFileTree(rootPath,folderWalker);
        }
        catch (IOException e) {e.printStackTrace();}
    }

    public static class FolderWalker extends SimpleFileVisitor<Path> {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
            if(attrs.isRegularFile()) {
                executor.execute(fileDataManager.addFileMap(new FileDataModel(path.toFile(), attrs.creationTime().toInstant(), attrs.lastAccessTime().toInstant())));
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException e) {
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) {
            return FileVisitResult.CONTINUE;
        }
    }
}

您可以設法通過使用計數信號量來限制進程。

這背后的概念很簡單:您從信號量上釋放的初始值 5_000 個許可開始; 每次您的代碼將一個新文件排入隊列時,它都需要一個許可。 當信號量用完許可時,您的代碼將等待(阻止調用semaphore.acquire() )直到再次釋放許可。 您現有的代碼每次消耗累積的數據時都必須release()允許。

上述概念的簡單實現是:

class FileDataManager {

    private static final int BATCH_SIZE = 5_000;
    private final Semaphore semaphore = new Semaphore(BATCH_SIZE);
    private Map<String, String> data = new HashMap<>(BATCH_SIZE);

    Runnable addFileMap(FileDataModel fileDataModel) {
        try {
            //Try to acquire a permit, or wait (blocking call) until a permit is available
            semaphore.acquire();
            return new Runnable() {
                @Override
                public void run() {
                    //Process file...
                    data.put(fileDataModel.toString(), fileDataModel.toString());
                }
            };
        } catch (InterruptedException ex) {
            Logger.getLogger(FileDataManager.class.getName()).log(Level.SEVERE, null, ex);
            throw new RuntimeException(ex);
        }

    }

    public int accumulatedFileCount() {
        return data.size();
    }

    public void releasePermits() {
        semaphore.release(BATCH_SIZE);
    }

}

另一個監視 map 的線程將:

//...
            if (fileDataManager.accumulatedFileCount() >= 5_000) {
                // store data in RDBMS
                fileDataManager.releasePermits();
            }
//...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM