如何实现多线程安全read/write锁(ConcurrentHashmap)
How to implement multiple threadsafe read/write locks (ConcurrentHashmap)
我有一个可以读取和写入多个文件的应用程序。目的是防止特定文件在被另一个线程写入时被读取或写入。我不想在写入单个文件时锁定所有文件的读写,因为这会导致不必要的锁定。
为了尝试实现这一点,我将 concurrentHashMap 与同步块结合使用,但如果有更好的解决方案,我愿意接受。
这是粗略的代码。
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);
}
如果多个线程尝试写入同一个文件,最后一个执行 move
的线程获胜。
我有一个可以读取和写入多个文件的应用程序。目的是防止特定文件在被另一个线程写入时被读取或写入。我不想在写入单个文件时锁定所有文件的读写,因为这会导致不必要的锁定。
为了尝试实现这一点,我将 concurrentHashMap 与同步块结合使用,但如果有更好的解决方案,我愿意接受。
这是粗略的代码。
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);
}
如果多个线程尝试写入同一个文件,最后一个执行 move
的线程获胜。