使用调度的执行程序而不是Java中的硬循环来监视目录 [英] Watch directory using scheduled executor instead of hard loop in Java

查看:46
本文介绍了使用调度的执行程序而不是Java中的硬循环来监视目录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的>上一个问题中我正在警告一个简单的练习,它监视目录中文件的更改.我从此oracle文档中获取了代码,并且有效没问题,除了我不确定的一点未经检查的强制警告.

In my previous question I was warking on a simple exercise that watched a directory for file changes. I took the code from this oracle docs, and it worked with no problem, except for the little unchecked cast warning I was unsure about.

此代码的下一个问题是,至少在理论上,它在线程内部放入了一个硬循环,该循环正在阻塞.现在,我知道,如果操作系统使用时间分片,那么即使硬循环也被拆分为小块,这些小块与应用程序正在运行的其他线程共享处理器的时间,实际上,我可以在硬循环中做出各种示例在不同线程中运行的线程不会互相阻塞(只要它们具有相同的优先级),即使在明确创建的只有一个内核的虚拟机上也是如此.

The next problem I have with this code is that it's putting a hard loop inside a thread, which is blocking, at least in theory. Now, I know that if the operating system uses time slicing, even the hard loop is split up in small chunks that share the processor's time with the other threads the application is running, and in fact I can make all sorts of examples where hard loops running in different threads don't block each other (as long as they have the same priority), even on a virtual machine expressly created with only one core.

但是,Java语言不能保证它用于时间管理或循环调度,而是用于线程管理.这取决于实际的VM实施和操作系统.因此,在研究本主题时,我得到的建议是编写代码,就好像它必须在循环线程调度上运行一样,从而避免在线程中放入硬循环,除非我的代码可以不断将控件回退给其他线程与 sleep() wait() yeld()等.(我可以想到一个GUI,其中主线程是一个监视事件,然后将控制权发回给侦听器以处理事件).

However, the Java language doesn't guarantee which kind of scheduling it uses for thread management, if it's time-slicing or round-robin; it depends on the actual VM implementation and operating system. So the advice I'm getting while studying the subject is to write code as if it had to run on a round-robin thread scheduling, thus avoiding putting hard loops in threads, unless my code can continuously yeld back the control to the other threads with sleep(), wait(), yeld(), etc. (I can think of a GUI where the main thread is the one with a hard loop watching for events, and sending control back to listeners to handle them).

但是,在我的情况下,我想不出一种方法在线程处理完文件更改后使其进入睡眠状态,或者将控件退回到主循环,因为核心思想基本上是不断询问如果文件系统有更改.所以我想到的是一个定期执行的执行程序,该执行程序定期调用监视线程.显然,这是在具有阻塞"线程和在文件系统发生更改时立即得到通知之间的折衷方案.因为在实际情况下,我将进行此练习,所以我可能不需要即时通知,对此我感到很满意.代码非常简单:

In my case, however, I couldn't think of a way to put the thread to sleep after it handled the file change, or to yeld the control back to the main loop, since the core idea is basically to continuously ask if there are changes to the filesystem. So what I came up to, is a scheduled executor that regularly calls the watching thread. Clearly, this is a tradeoff between having a "blocking" thread, and being immediately notified when a filesystem change happens. Since in the real case I'm going to put this exercise into, I probably won't need immedite notification, I'm happy with that. The code is very straightforward:

// imports...
public class Main
{
    public static FileSystem fs;
    public static Path dir;
    public static WatchService watcher;
    public static WatchKey key;

    public static void main(String[] args)
    {
        fs = FileSystem.getDefault();
        dir = fs.getPath(".");

        try {
            watcher = fs.newWatchService();
            dir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
        } catch (IOException e) {
            System.err.println(e.getMessage());
            return;
        }

        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable()
            {
                public void run()
                {
                    Main.key = Main.watcher.poll();
                    if (null == Main.key)
                        return;

                    for (WatchEvent<?> event : Main.key.pollEvents()) {
                        WatchEvent.Kind<?> kind = event.kind();
                        if (kind == StandardWatchEventKinds.OVERFLOW)
                            continue;

                        @SuppressWarnings("unchecked");
                        WatchEvent<Path> ev = (WatchEvent<Path>)event;
                        Path file = ev.context();
                        System.out.println(file);

                        boolean valid = Main.key.reset();
                        if (!valid)
                            System.err.println("Invalid key!");
                    }
                }
            }, 0, 1, TimeUnit.SECONDS);
    }
}

所以我的问题是:

  1. 我把这个推得太远了吗?我的意思是,实际上,这是一种很好的做法,是在线程中阻塞代码,还是在真正的情况下不存在时间分片,这种情况很少见,因此我可以安全地在线程中放入硬循环,也许可以这样做只有当我知道我的代码要在保证轮循的嵌入式设备上运行时,这种东西才会出现?

  1. Am I pushing this too far? I mean, is it actually a good practice to care this much about blocking code in threads, or are the real cases where time slicing is not present, so rare, that I can safely put a hard loop inside a thread, and maybe do this kind of stuff only when I know that my code is going to run maybe on an embedded device with guaranteed round-robin?

在这种特殊情况下,还有其他方法可以避免硬循环吗?也许我想不到一些巧妙地使用线程控制方法( sleep() wait()等)?

Is there any other way to avoid the hard loop in this particular case? Maybe some clever use of thread control methods (sleep(), wait(), etc.), that I can't think of?

非常感谢,对于冗长的帖子深表歉意.

Thank you very much, and sorry for the long post.

推荐答案

正如注释中指出的那样,在提供新密钥之前, take()方法不会阻止线程执行,但是它使用类似于 wait()方法的机制来使线程进入睡眠状态.

As pointed out in the comments, the take() method doesn't block the thread execution until a new key is provided, but it uses a mechanism similar to the wait() method to put the thread to sleep.

我还发现了这篇文章,其中指出了 WatcherService 利用本机文件事件通知机制(如果可用)(明显的例外是

I also found this post where it's pointed out that the WatcherService exploit the native file event notification mechanism, if available (with a notable exception being the OSX implementation).

因此,要回答我自己的问题,在硬循环中使用 take()不会阻塞线程,因为它会自动使线程进入睡眠状态,让其他线程使用CPU,直到文件更改通知来自操作系统.

So, to answer my own question, using take() inside a hard loop does not block the thread, because it automatically put the thread to sleep, letting the other threads use the CPU, until a file change notification comes from the operating system.

这篇关于使用调度的执行程序而不是Java中的硬循环来监视目录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆