我想创建一个java应用程序,在访问令牌的帮助下,我们想为多个用户进行rest调用。每个用户使用1个线程。我正在使用的访问令牌有效期为1小时。一旦令牌过期,我将收到401错误,并且必须为所有线程更新令牌。然后继续。我在考虑使用一个volatile变量,我已经将其设置为静态来更新所有线程。我的要求是,当我知道其中一个线程的令牌已经过期时,我希望所有的线程停止处理,等待新的令牌生成(这需要几秒钟)。而且一旦生成,令牌应该自动更新,没有每个线程失败,因为过期的令牌。
下面是我编写的示例代码:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Sample {
public static void main(String[] args) {
String[] myStrings = { "User1" , "User2" , "User3" };
ScheduledExecutorService scheduledExecutorService = Executors
.newScheduledThreadPool(myStrings.length);
TokenGenerator.getToken();
for(String str : myStrings){
scheduledExecutorService.scheduleAtFixedRate(new Task(str), 0, 5, TimeUnit.SECONDS);
}
}
}
class Task implements Runnable{
private String name;
public Task(String name){
this.name = name;
}
@Override
public void run() {
getResponse(TokenGenerator.token);
}
private void getResponse(String token) {
// Make http calls
// if token expire , call getToken again. Pause all the running threads , and
// update the token for all threads
TokenGenerator.getToken();
}
}
class TokenGenerator {
public static volatile String token;
public static void getToken() {
token = "new Token everytime";
}
}
有没有更好的方法来解决这个问题?上面的代码不能满足我的用例,因为一旦一个线程开始生成一个新的令牌,所有其他线程都不会被暂停。
3条答案
按热度按时间x7yiwoj41#
您可以将令牌放在AtomicReference中,然后使用Semaphore暂停线程:
X1 M0 N1 X在X1 M2 N1 X上使用原子X1 M1 N1 X以确保只有一个线程将刷新令牌,然后在X1 M4 N1 X上调用X1 M3 N1 X以使其它线程等待直到令牌被刷新。X1 M5 N1 X如果令牌不是X1 M6 N1 X则返回令牌,else在
semaphore
上等待-这是在循环中完成的,因为线程可能必须在tokenRef
被设置为null
和drainPermits()
在semaphore
上被调用之间旋转几个周期。编辑:修改了
refreshToken(Token oldToken)
的签名,以便传入旧令牌,而不是在方法内部读取-这是为了防止出现以下情况:RESTService_A刷新令牌,RESTService_B使用旧的过期令牌获得401,然后RESTService_B在RESTService_A完成对refreshToken
的调用后调用refreshToken
,使用新的签名,RESTService_B将传入旧的过期令牌,因此当旧令牌无法匹配新令牌时,compareAndSet
调用将失败,从而导致refreshToken
仅被调用一次。rqqzpn5f2#
您可以使用以下模式,仅使用getter访问令牌,并在收到错误响应时调用
loadToken
。要解决暂停线程的问题,您可以在任何需要暂停
getToken()
的地方调用getToken()
,Thread
将在加载令牌当前处于活动状态时自动阻塞。ahy6op9u3#
因为你需要做两件事(http调用和更新令牌),你可以尝试双向检查。
一个用于检查令牌是否为
is expired or not
,另一个用于检查是否有任何其它线程正在尝试update the token
。这里有一个小代码来演示这个想法(它的方式有点脏,所以可能需要一些清理)