我目前正在研究实现一个会话管理器java类,它提供了按需读取和刷新会话令牌的功能。如果正在刷新会话令牌(即从服务器获取),则会话令牌读取器应该阻塞,直到刷新完成。同样,刷新请求被阻止,直到任何正在进行的读取未完成。由于会话令牌读取请求与会话令牌刷新请求相比非常频繁,因此我决定使用ReentrantReadWriteLock来实现读取和刷新之间的同步。以下是它的外观:
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;
}
}
我的第一次尝试是在写锁上使用tryLock(),这样如果它已被锁定以便写入,那么tryLock()将返回false然后获取读锁并阻塞,直到写锁被释放,从而重新安排读取阻塞的线程以完成读取。此逻辑适用于多个线程同时调用refreshSession()从而仅允许一个线程启动会话令牌刷新而所有其他线程通过并阻塞读取锁定的情况。
但是,如果一个线程刚刚获得了一个读锁(通过调用readToken())而另一个线程调用了refreshToken()来获取一个写锁,那么上面的逻辑会失败 - 在这种情况下tryLock()会失败结果刷新请求。
作为替代方案,我正在查看readWriteLock.isWriteLocked()方法,该方法检查是否有任何线程获得了写锁:
String refreshToken() {
try{
if (!readWriteLock.isWriteLocked()) {
readWriteLock.writeLock().lock();
//fetch session from server and store on disk
} finally{
readWriteLock.writeLock().unlock();
}
}
return readToken();
}
但是,我没有太多使用此方法的经验,并且不完全确定它会产生的同步影响,因为我想确保只有一个线程可以获取写锁定,后续请求会进入读取状态。 任何建议/指针都将非常受欢迎。
答案 0 :(得分:1)
您可以在那里引入新的ReentrantLock
和tryLock
。如果存在作家,ReentrantLock只承诺一个作者,而很快失败。
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();
}
因此只有一个线程会尝试编写。在写作进展的过程中,任何线程都无法读取。