0

EDIT 2: I've updated my WatcherService and wrapped the Path within a synchronized block:

    private void  registerAll(final Path start) throws IOException {
        Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir,BasicFileAttributes attrs) throws IOException {
                synchronized(dir){
                    logger.debug("Dir: " + dir.toString());
                    register(dir);
                    return FileVisitResult.CONTINUE;
                }
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                synchronized(file){
                    logger.debug("File: " + file.getFileName()); 
                    //register(file);
                    file.toFile().setLastModified(DateTime.now().getMillis());
                    return FileVisitResult.CONTINUE;
                }    
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException e) {
                synchronized(file){
                    logger.debug("Error visiting file {} with exception {}",file.toFile().getAbsolutePath(),e.getCause());
                    e.printStackTrace();
                    file.toFile().setLastModified(DateTime.now().getMillis());
                    return FileVisitResult.CONTINUE;
                }    
            }
        });
}

Further down in class

 WatchKey key;
 try {
    key = watcher.take();
 } catch (InterruptedException x) {
        return;
 }

 Path dir = keys.get(key);
 synchronized(dir){
    if (dir == null) {
         System.err.println("WatchKey not recognized!!");
           continue;
    }
        // process file functionality:  Add path to DB, etc
 }

Thoughts on approach? What benefit would a channel lock provide for me vs the current implementation?

EDIT: Do I need to have the locks on both threads or just one?

I have two threads. One thread watches for changes to a directory and writes those changes to a DB. The second thread periodically reads the file paths from the database and loads the files into memory. I am running into an issue when the threads are executing at the same time. One is possibly updating its lastModified date while the other is trying to read it into memory.

I'm confused as to which approach I should take. Can I write a synchronization block around the reference to the file or do I need to acquire a readWrite lock, create a channel?

Dan
  • 979
  • 1
  • 8
  • 29
  • There are a *lot* of options here. For example, proper use of transactions when writing / reading DB as well as setting the [isolation level](http://dotnetspeak.com/2013/04/transaction-isolation-levels-explained-in-details) to serializable, or at least read-committed, could be sufficient. Or throw the entire operation in a big `synchronized` block. Or if you have objects for individual files, a finer grained synchronization block could work. For your situation, I'd recommend the db transaction + isolation level approach (isolation level depends on situation, use your judgment). – Jason C Mar 18 '14 at 02:50

1 Answers1

0

It would be better if you create a channel with synchoronization as it will properly manage read and write, also it is more efficient than the synchronization block. Also in case of file handling it better to use this.

Ankur Kumawat
  • 446
  • 5
  • 21
  • Do I have to create a channel lock on every thread or just one? I'm using this (http://stackoverflow.com/questions/128038/how-can-i-lock-a-file-using-java-if-possible) as my example. – Dan Mar 18 '14 at 13:27
  • create it for read and write operations, multiples can read together but none can read or write while one is writing... – Ankur Kumawat Mar 19 '14 at 06:09