I am currently looking at implementing a session manager java class which provides functionality to read and refresh session tokens on demand. If the session token is being refreshed (i.e. being fetched from server) then session token readers should block until the refresh is complete. Similarly, a refresh request is blocked until any ongoing reads are not complete. Since session token read requests are quite frequent as compared to session token refresh requests, i have decided to use the ReentrantReadWriteLock to achieve the synchronisation between read and refresh. Here is how it looks:
String refreshToken() {
try{
if (readWriteLock.writeLock().trylock()) {
//fetch session from server and store on disk
}
} finally {
readWriteLock.writeLock().unlock();
}
return readToken();
}
String readToken() {
try {
readWriteLock.readLock().lock();
//read token from disk
} finally {
readWriteLock.readLock().unlock();
}
return token;
}
}
My first attempt was to use a tryLock() on the write lock so that if it is locked for writing already then, tryLock() will return false and then acquire a read lock and block until the write lock is released thereby rescheduling read-blocked threads to complete the read. This logic works well for the case where multiple threads invoke refreshSession() at the same time thereby allowing only one thread to initiate the session token refresh whereas all other threads fall through and block on the read lock.
However, the logic above would fail if a thread had just acquired a read lock (by calling readToken()) and another thread invokes refreshToken() to acquire a write lock - the tryLock() would fail in this case missing the refresh request as a result.
As an alternative, I was looking at the readWriteLock.isWriteLocked() method that checks if any thread has acquired the write lock:
String refreshToken() {
try{
if (!readWriteLock.isWriteLocked()) {
readWriteLock.writeLock().lock();
//fetch session from server and store on disk
} finally{
readWriteLock.writeLock().unlock();
}
}
return readToken();
}
However, i do not have much experience with this method and not entirely sure about the synchronisation repercussions it would have since i want to ensure only one thread can acquire the write lock and subsequent requests fall through to a read. Any suggestions/ pointers would be most appreciated.
You can introduce a new ReentrantLock
and tryLock
there. The ReentrantLock promises only one writer while fails quickly if there exists a writer.
ReentrantLock lock = new ReentrantLock();
public String refreshToken() {
if (lock.tryLock()) {
readWriteLock.writeLock().lock();
try {
// fetch session from server and store on disk
} finally {
readWriteLock.writeLock().unlock();
}
}
return readToken();
}
So only one thread will ever try to write. And no threads can read while writing is progressing.