我对 ReentrantReadWriteLock 的使用有什么问题?
What's wrong with my usage of ReentrantReadWriteLock?
我在使用 ReentrantReadWriteLock
时遇到了问题。当我尝试擦除文件时线程挂起。我有一个预定的读取操作和最终的写入操作(当用户按下按钮时),它们使用 ReentrantReadWriteLock
的一个实例。接下来的代码看起来不适合使用,抱歉,为了简单起见,我把所有的东西都放在了一个地方。
public class FileDB {
private static final String ORDERS_FILENAME = "orders.tsv";
private ReadWriteLock ordersLock;
private FileDB() {
ordersLock = new ReentrantReadWriteLock();
// Swing Timer
ordersTimer = new Timer(0, (ActionEvent e) -> {
readFileSplittedByTab("orders.tsv", 5, ordersLock);
});
ordersTimer.setDelay(5 * 1000); // 5 sec
ordersTimer.start();
}
private List<String[]> readFileSplittedByTab(String filePath,
int columns, ReadWriteLock lock) {
lock.readLock().lock();
File file = new File(filePath);
// if file is absent or empty return empty list
if (!file.exists() || file.length() == 0)
return new ArrayList<String[]>();
List<String> lines = null;
try {
lines = Files.readAllLines(Paths.get(file.getAbsolutePath()));
} catch (IOException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
List<String[]> splittedFile = new ArrayList<>();
String[] parts = null;
for (String line : lines) {
parts = line.split("\t");
if (parts.length != columns) // skip bad string
continue;
splittedFile.add(parts);
}
return splittedFile;
}
private void wipeFile(String filePath, ReadWriteLock lock) {
PrintWriter printWriter = null;
try {
lock.writeLock().lock();
Files.newBufferedWriter(Paths.get(filePath), StandardOpenOption.TRUNCATE_EXISTING).close();
} catch (IOException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
}
然后这样写操作:
wipeFile(ORDERS_FILENAME, ordersLock);
当 wipeFile()
方法第一次触发时,一切正常。但是从第二次尝试开始,它挂在 lock.writeLock().lock()
上;
我试图从另一个线程调用 wipeFile()
方法,因为有人写道,写锁不应该在带有读锁的线程中使用。
Executors.newSingleThreadExecutor().execute(() -> {
wipeFile(ORDERS_FILENAME, ordersLock);
});
但这无济于事,另一个线程也挂了。
所以,问题是我对 ReentrantReadWriteLock 的使用有什么问题?
错误的是您在擦除文件(删除或文件长度等于 0)后从未释放读锁:
lock.readLock().lock();
File file = new File(filePath);
// if file is absent or empty return empty list
if (!file.exists() || file.length() == 0) {
// lock.readLock().unlock(); // this line is missing
return new ArrayList<String[]>();
}
我在使用 ReentrantReadWriteLock
时遇到了问题。当我尝试擦除文件时线程挂起。我有一个预定的读取操作和最终的写入操作(当用户按下按钮时),它们使用 ReentrantReadWriteLock
的一个实例。接下来的代码看起来不适合使用,抱歉,为了简单起见,我把所有的东西都放在了一个地方。
public class FileDB {
private static final String ORDERS_FILENAME = "orders.tsv";
private ReadWriteLock ordersLock;
private FileDB() {
ordersLock = new ReentrantReadWriteLock();
// Swing Timer
ordersTimer = new Timer(0, (ActionEvent e) -> {
readFileSplittedByTab("orders.tsv", 5, ordersLock);
});
ordersTimer.setDelay(5 * 1000); // 5 sec
ordersTimer.start();
}
private List<String[]> readFileSplittedByTab(String filePath,
int columns, ReadWriteLock lock) {
lock.readLock().lock();
File file = new File(filePath);
// if file is absent or empty return empty list
if (!file.exists() || file.length() == 0)
return new ArrayList<String[]>();
List<String> lines = null;
try {
lines = Files.readAllLines(Paths.get(file.getAbsolutePath()));
} catch (IOException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
List<String[]> splittedFile = new ArrayList<>();
String[] parts = null;
for (String line : lines) {
parts = line.split("\t");
if (parts.length != columns) // skip bad string
continue;
splittedFile.add(parts);
}
return splittedFile;
}
private void wipeFile(String filePath, ReadWriteLock lock) {
PrintWriter printWriter = null;
try {
lock.writeLock().lock();
Files.newBufferedWriter(Paths.get(filePath), StandardOpenOption.TRUNCATE_EXISTING).close();
} catch (IOException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
}
然后这样写操作:
wipeFile(ORDERS_FILENAME, ordersLock);
当 wipeFile()
方法第一次触发时,一切正常。但是从第二次尝试开始,它挂在 lock.writeLock().lock()
上;
我试图从另一个线程调用 wipeFile()
方法,因为有人写道,写锁不应该在带有读锁的线程中使用。
Executors.newSingleThreadExecutor().execute(() -> {
wipeFile(ORDERS_FILENAME, ordersLock);
});
但这无济于事,另一个线程也挂了。
所以,问题是我对 ReentrantReadWriteLock 的使用有什么问题?
错误的是您在擦除文件(删除或文件长度等于 0)后从未释放读锁:
lock.readLock().lock();
File file = new File(filePath);
// if file is absent or empty return empty list
if (!file.exists() || file.length() == 0) {
// lock.readLock().unlock(); // this line is missing
return new ArrayList<String[]>();
}