java - WatchService 大量目录(递归)

我想检测目录中的变化,所以我使用 WatchService 来实现

public class DirWatcher implements Runnable {

    private Path path;
    private ExecutorService exe;

    public DirWatcher(Path path, ExecutorService exe) {
        this.path = path;
        this.exe = exe;
    }

    public void start() throws Exception {
        WatchService watchService = FileSystems.getDefault().newWatchService();
        path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
        WatchKey key;
        while ((key = watchService.take()) != null) {
            for (WatchEvent<?> event : key.pollEvents()) {
                if(isFileEvent(event)) {
                    // do stuff with file
                } else if(isNewDirCreated(event)) {
                    Path dir = getPath(event, path);
                    DirWatcher newWatcher = new DirWatcher(dir, exe);
                    exe.execute(newWatcher);
                }
            }
            key.reset();
        }

        watchService.close();
    }

    public void run() {
        try {
            start();
        } catch(Exception e) {
        }
    }

    //Other methods
}

这是主要方法

public class DirectoryWatcherExample {

    public static void main(String[] args) throws Exception {
        Path root = getRootPath();
        ExecutorService exe = Executors.newFixedThreadPool(//HOW BIG THE POOL SHOULD I INIT? THE NUMBER OF DIRECTORIES IS LARGE (> 50000))
        DirWatcher watcher = new DirWatcher(root, exe);
        exe.execute(watcher);
        List<Path> paths = listRecrursive(root);
        paths.stream().map(p -> new DirWatcher(p, exe)).forEach(exe::execute);
    }
}

我的问题是:我应该如何初始化线程池?由于任务数量巨大(> 50000)。它会影响服务器(64 Gb RAM)吗?

ForkJoinPool 和 RecursiveTask 在这种情况下有用吗?如果是,你能提供伪代码吗?如果没有,是否有任何优化的解决方案?谢谢

回答1

每个文件系统只需要一个新的 WatchService,而不是每个目录,并且只需要一个轮询循环/线程来处理每个 WatchService

正如您现在所拥有的那样,您已经设置了一个 WatchService 并为每个文件夹设置轮询循环,这对于 50,000 个文件夹来说很难扩展( - 没有 LOOM 虚拟线程)。固定大小的线程池是不合适的。

而是跟踪 FilesystemWatchService 的映射并将新文件夹注册到其相应文件系统的单个 WatchService

为每个新的 WatchService 启动一个新的服务/轮询线程,该线程将处理您从同一文件系统注册的许多文件夹。

对于许多应用程序,一对 WatchService+轮询线程可以处理同一文件系统的所有文件夹。每个 WatchService 的轮询事件将用于更改许多文件夹 - 并且这些事件会告诉您哪个文件夹。

为简单起见,您可能会考虑额外的 WatchService+thread 对专用于特定的子树 - 但每个文件夹不要多一个 WatchService+thread,因为这意味着 1,000 个线程。

请注意,无论您决定设置多少 WatchService 和线程,事件轮询循环都非常冗长,因此您应该始终整理操作以供以后执行。将其视为 JavaFx/Swing/AWT UI 事件处理程序 - 记录要处理的任务,以便在轮询循环之外执行操作。请参阅此https://stackoverflow.com/questions/65223686/java-watchservice-perform-action-on-event-using-threads/65251819#65251819的示例。

相似文章

java - 异常后重启 WatchService

我在我的Spring引导应用程序中使用Java的WatchServiceAPI来监视目录,并对创建的文件执行一些操作。这个过程是异步执行的:它在应用程序准备就绪后立即自动启动,并在后台监视目录,直到应...

随机推荐

最新文章