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

标签 java concurrency synchronized concurrenthashmap

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

为了尝试实现这一目标,我将并发HashMap与同步块(synchronized block)结合使用,但如果有更好的解决方案,我愿意接受。

这是粗略的代码。

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 中的值 - 如果发生这种情况,同步会失败吗?

最佳答案

我每次都会编写一个新的临时文件,并在完成后重命名它。重命名是原子的。

// a unique counter across restarts
final AtomicLong counter = new AtomicLong(System.currentTimeMillis()*1000);

private void createCache(String templatePath, String cachePath) {
    //get template
    String temp = getTemplate(templatePath);

    Path path = Paths.get(cachePath);
    Path tmpPath = Paths.get(path.getParent().toString(), counter.getAndIncrement() + ".tmp");
    // save cache file
    Files.write(tmpPath, temp.getBytes(StandardCharsets.UTF_8));
    Files.move(tmpPath, path, ATOMIC_MOVE, REPLACE_EXISTING);
}

如果多个线程尝试写入同一个文件,则最后一个执行移动的线程获胜。

关于java - 如何实现多个线程安全的读/写锁(ConcurrentHashmap),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51177235/

相关文章:

java - OutOfBoundsException 问题,Java

java - 多线程消息有序处理

Python:使用 Bottle 和 Tornado Web 服务器来处理并发连接

java - 通过锁链锁

java - 为什么这些线程不按顺序运行?

java - 即使 Android 上的内存非常低,垃圾收集器也不会运行

java - 突出显示 jTextField 中用户输入搜索的所有单词

android - 同步块(synchronized block)android

java - 如果底层Java进程终止,如何使gradle运行终止?

java - 'synchronized' 是什么意思?