为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕容708150 2021-05-01 04:31:28
我有一个可以读取和写入许多文件的应用程序。目的是防止在另一个线程写入特定文件时读取或写入该文件。我不想在写入单个文件时锁定所有文件的读写,因为这会导致不必要的锁定。为了实现这一目标,我将并发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中的值-如果发生这种情况,同步是否会失败?
查看完整描述

1 回答

?
森林海

TA贡献2011条经验 获得超2个赞

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


// 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);

}

如果多个线程尝试写入同一文件,则最后一个执行move胜利。


查看完整回答
反对 回复 2021-05-12
  • 1 回答
  • 0 关注
  • 147 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信