I have a trouble with ReentrantReadWriteLock
. Thread hangs when I trying to wipe file. I have a scheduled read operation and eventual write operation(when user presses the button) which use one instance of ReentrantReadWriteLock
. Next code looks unsuitable for use, sorry, I put everything in one place for simplicity.
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();
}
}
}
And write operation like that:
wipeFile(ORDERS_FILENAME, ordersLock);
When wipeFile()
method fires for the first time everything is working. But starting from the second attempt it hangs on lock.writeLock().lock()
;
I tried to call wipeFile()
method from another thread because guys wrote that write lock should not be used in the one thread with read lock.
Executors.newSingleThreadExecutor().execute(() -> {
wipeFile(ORDERS_FILENAME, ordersLock);
});
But it does not help, another thread hangs too.
So, the question is what's wrong with my usage of ReentrantReadWriteLock?
What is wrong is that you never release the readlock after the file is wiped (deleted or file length equal 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[]>();
}