Java 在同一个文件上同步,但没有区别
Java Synchronized on the same file, but not different
我有这个静态 class:
public class FileManager{
....
public static void writeOnFile(String something, String filepath){
File f= new File(filepath);
// Append
PrintWriter writer = new PrintWriter(new FileWriter(f, true));
writer.append(something);
}
...
}
有很多方法,上面这个就是其中之一。
我想做的是,如果两个调用者写入同一个文件,写入应该是互斥的。但是当调用者写入不同的文件时,这不会发生(他们不会互斥写入)。
下面这个版本:
public class FileManager{
....
public synchronized static void writeOnFile(String something, String filepath){
File f= new File(filepath);
// Append
PrintWriter writer = new PrintWriter(new FileWriter(f, true));
writer.append(something);
}
...
}
我不认为那是我想要完成的。在这种情况下,调用者将以互斥方式写入,即使他们写入的文件不同。
我想问:这个第二个版本:
public class FileManager{
....
public static void writeOnFile(String something, String filepath){
File f= new File(filepath);
// Append
synchronized(f){
PrintWriter writer = new PrintWriter(new FileWriter(f, true));
writer.append(something);
}
}
...
}
行得通吗?如果没有,我是否必须创建一个包含每个文件的文件路径的对象才能按我的意愿使用锁?
只有在同一个实际对象上完成同步才会起作用。您的第二个版本将不起作用,因为它创建了一个新对象,因此创建了一个新锁。您需要的是锁的注册表。一个小例子,使用 not synchronized but ReentrantLock
:
private static final Map<String, Lock> LOCKS = new ConcurrentHashMap<>();
...
Lock lock = LOCKS.computeIfAbsent(filepath, p -> new ReentrantLock());
lock.lock();
try {
....
} finally {
lock.unlock();
}
每次使用相同的 filepath
值调用方法时,ConcurrentHashMap
和 computeIfAbsent
的组合应该产生相同的 Lock
对象。
另一种选择可能是使用 FileLock
。它使用本机锁定机制(如果它确实存在),并且基于实际文件,而不是 Java 个对象。
我有这个静态 class:
public class FileManager{
....
public static void writeOnFile(String something, String filepath){
File f= new File(filepath);
// Append
PrintWriter writer = new PrintWriter(new FileWriter(f, true));
writer.append(something);
}
...
}
有很多方法,上面这个就是其中之一。
我想做的是,如果两个调用者写入同一个文件,写入应该是互斥的。但是当调用者写入不同的文件时,这不会发生(他们不会互斥写入)。
下面这个版本:
public class FileManager{
....
public synchronized static void writeOnFile(String something, String filepath){
File f= new File(filepath);
// Append
PrintWriter writer = new PrintWriter(new FileWriter(f, true));
writer.append(something);
}
...
}
我不认为那是我想要完成的。在这种情况下,调用者将以互斥方式写入,即使他们写入的文件不同。
我想问:这个第二个版本:
public class FileManager{
....
public static void writeOnFile(String something, String filepath){
File f= new File(filepath);
// Append
synchronized(f){
PrintWriter writer = new PrintWriter(new FileWriter(f, true));
writer.append(something);
}
}
...
}
行得通吗?如果没有,我是否必须创建一个包含每个文件的文件路径的对象才能按我的意愿使用锁?
只有在同一个实际对象上完成同步才会起作用。您的第二个版本将不起作用,因为它创建了一个新对象,因此创建了一个新锁。您需要的是锁的注册表。一个小例子,使用 not synchronized but ReentrantLock
:
private static final Map<String, Lock> LOCKS = new ConcurrentHashMap<>();
...
Lock lock = LOCKS.computeIfAbsent(filepath, p -> new ReentrantLock());
lock.lock();
try {
....
} finally {
lock.unlock();
}
每次使用相同的 filepath
值调用方法时,ConcurrentHashMap
和 computeIfAbsent
的组合应该产生相同的 Lock
对象。
另一种选择可能是使用 FileLock
。它使用本机锁定机制(如果它确实存在),并且基于实际文件,而不是 Java 个对象。