Wednesday, January 11, 2012

Java 7 new features - 4. NIO2 : B. Watch Service


<< Previous Table of Categories Next >>


In some high volume traffic system (e.g. telecommunication environment), some resource files (for example configuration files) needed to be cached in the memory. When the files are changed, the system needs to be aware and reload them into the memory. Another case is that when we need to reduce the system down time as little as possible, we also need to have a system which can support hot deployment and dynamic reloading because customers may not be able to afford to do stop and restart frequently. In both cases, we need to have a mechanism to detect whether the original resource has been changed or not. In previous Java version(<7), one of methods we used is checking the last modified timestamps of those files. The following code snippet can be seen everywhere:
 
 ...
 private long lastModifiedTime = 0;
 ...
 long fileModified = file.lastModified();
 if (fileModified > lastModifiedTime)
 {
   //reload the resource files 
   reload();
   lastModifiedTime = fileModified;
 }
 ...
From Java 7, we can easily use the Watch Service API which uses the underlying file system functionalities to watch the file system for changes (Create, Modify, Overflow, Delete). To meet the requirement mentioned above, we can write some code like below:
 
 ...
 private final static String DITECTORY_TO_WATCH = "some_directory";
 private final static String FILE_TO_WATCH = "some_file";
 ...
 FileSystem fs = FileSystems.getDefault();
 WatchService ws = fs.newWatchService();
 Path path = fs.getPath(DITECTORY_TO_WATCH);
 path.register(ws, StandardWatchEventKinds.ENTRY_MODIFY);
 while(true)
 {
   WatchKey key = ws.take();
   List<Watchevent<?>> events = key.pollEvents();
   for (WatchEvent event: events)
   {
     if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY)
     {
      if(event.context().toString().equals(FILE_TO_WATCH))
      {
  //reload the resource files 
  reload();
      }
     }
   }
   key.reset();
 }
 ...
This will be much more efficient than the previous solution. Howerver, you need to pay attention of the following points:
  1. please don't forget put the following line (which can be ignored by some developer) in your infinite loop:
    key.reset()
    Without this, the system is not able to detect the future change.
  2. Inside the "WatchService", "ReentrantLock" is used (inside the LinkedBlockingDeque class).
    So the Watch Service needs to be in a separate Thread from your other paralleling running tasks.
  3. Instead of using ws.take(), you can also use ws.poll. Their differencs are described below:
    • pull(): Retrieves and removes the next watch key, or if no key is availabe, a null will be returned immediately.
    • poll(long timeout, TimeUnit unit): Retrieves and removes the next watch key, waiting up to the specified wait time if still no key available, then it will return null.
    • take(): Retrieves and removes next watch key, keeps waiting until there is a key available.

No comments:

Post a Comment