Search this site

 Home  I/O  Buffering  Character streams  NIO intro  Buffers  Channels  Buffer performance

Search this site:
Threads Database Profiling Regular expressions Random numbers Compression Exceptions C Equivalents in Java

 What do you think of this article? Did it help you? Found a mistake? Feedback and suggestions here

Polling WatchService in a separate thread

As mentioned earlier in our WatchService tutorial, we will usually want to poll for file modifications in a separate thread. This means that we need to pay attention to a few issues of thread-safety. Key points, some of which we have touched upon, are as follows:

  • we will usually run our polling loop in a separate thread to the thread (often the UI event thread) which handles the "logic" of registering paths, displaying modifications etc;
  • the Path class is thread-safe (because all of its member variables are final): we can happily pass around instances of Path without worrying about thread-safety;
  • we must ensure that any reference to our WatchService is final, since it will be referred to by different threads;
  • any object mapping WatchKeys to their corresponding Paths, which will usually be referred to in both the "logic" thread of your application when registering directories and also in the processing thread, must be accessed in a thread-safe way, either via synchronization or by using an inherently thread-safe map such as a ConcurrentHashMap;
  • in your polling loop and modification processing method, you may need to think about which thread you pass processing to: for example, if you wish to update a user interface component to notify the user that the file has been modified, you may need to do so inside an invokeLater() construct.

How to run the processing loop in a separate thread

We will typically run the file modification processing loop in its own thread, e.g. as follows:

  private volatile Thread processingThread;

  public void startListening() {
    processingThread = new Thread() {
      public void run() {
        try {
          processFileNotifications();
        } catch (InterruptedException ex();
        processingThread = null;
      }
    };
    processingThread.start();
  }

  public void shutDownListener() {
    Thread thr = processingThread;
    if (thr != null) {
      thr.interrupt();
    }
  }

Then in our process() method, for example:

  private void process(Path dir, Path file, WatchEvent.Kind evtType) {
    if (UI needs updating) {
      final Path fileRef = file;
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          // ... update UI with "fileRef"
        }
      });
    }
  }

Notice the slightly awkward syntax here: our update code, inside the embedded run() method, will run in a separate thread. Therefore, any objects from the process() method that we also wish to reference from inside the update thread must be refenced via final references. Hence, we create as an example the final reference fileRef in order to refer to the path of the file (but we could create similar references to dir, evtType or any other variable created via process().

When do we not need a separate processing thread?

If your application is going to run as a "standalone" process whose only purpose is to monitor a particular directory (e.g. system log files) and no user interaction is required, then you may be able to run the modification processing loop, and possibly your whole application, in a single thread. The decision will depend on whether you require your application to perform other tasks while file notification processing is going on.

comments powered by Disqus

Written by Neil Coffey. Copyright © Javamex UK 2012. All rights reserved.