2

我目前正在考虑实现一个会话管理器 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();
}

但是,我对这种方法没有太多经验,也不完全确定它会产生的同步影响,因为我想确保只有一个线程可以获得写锁,并且后续请求会被读取。任何建议/指针将不胜感激。

4

1 回答 1

1

你可以在那里介绍一个新ReentrantLocktryLock。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();
}

所以只有一个线程会尝试写。并且在写入过程中没有线程可以读取。

于 2015-10-08T17:45:03.533 回答