猿问

如何实现多个线程安全的读/写锁(ConcurrentHashmap)

我有一个可以读取和写入许多文件的应用程序。目的是防止在另一个线程写入特定文件时读取或写入该文件。我不想在写入单个文件时锁定所有文件的读写,因为这会导致不必要的锁定。


为了实现这一目标,我将并发HashMap与同步化块结合使用,但是如果有更好的解决方案,我可以接受。


这是粗略的代码。


private static final ConcurrentMap<String, String> lockMap = new ConcurrentHashMap();



private void createCache(String templatePath, String cachePath){


//get template 

String temp = getTemplate(templatePath);


String myRand = randomString();

lockMap.put(cachePath,myRand);


// save cache file

  try {

    // ** is  lockMap.get(cachePath) still threadsafe if another thread has changed the row's value?

    synchronized ( lockMap.get(cachePath) ){

      Files.write(Paths.get(cachePath),temp.getBytes(StandardCharsets.UTF_8));

    }

  } finally {

    // remove lock if not locked by another thread in the meantime

    lockMap.remove(cachePath, myRand);

  }


}



private String getCache(String cachePath){


 String output = null;


  //only lock if this specific file is being written at the moment

  if ( lockMap.contains(cachePath) ){

        synchronized ( lockMap.get(cachePath) ){

            output = getFile(cachePath);

        }

    } else {

        output = getFile(cachePath);

    }


  return output;


}


// main event        

private String cacheToString (String templatePath, String cachePath){


  File cache = new File(cachePath);


  if ( !cache.exists() ){

    createCache(templatePath, cachePath)

  }


  return getCache(cachePath);


}

我的问题是,尽管该线程仅在另一个线程未更改请求的文件的锁的情况下才删除该文件的锁,但是另一个线程仍然有可能为该条目更新lockMap中的值-如果发生这种情况,同步是否会失败?


慕容708150
浏览 148回答 1
1回答

森林海

我每次都会写一个新的临时文件,并在完成后将其重命名。重命名是原子的。// a unique counter across restartsfinal AtomicLong counter = new AtomicLong(System.currentTimeMillis()*1000);private void createCache(String templatePath, String cachePath) {&nbsp; &nbsp; //get template&nbsp; &nbsp; String temp = getTemplate(templatePath);&nbsp; &nbsp; Path path = Paths.get(cachePath);&nbsp; &nbsp; Path tmpPath = Paths.get(path.getParent().toString(), counter.getAndIncrement() + ".tmp");&nbsp; &nbsp; // save cache file&nbsp; &nbsp; Files.write(tmpPath, temp.getBytes(StandardCharsets.UTF_8));&nbsp; &nbsp; Files.move(tmpPath, path, ATOMIC_MOVE, REPLACE_EXISTING);}如果多个线程尝试写入同一文件,则最后一个执行move胜利。
随时随地看视频慕课网APP

相关分类

Java
我要回答