我有以下用例:我的Android应用程序向服务器发出多个并发HTTP请求。如果请求产生“不正确的令牌”错误,则应用程序应通过向服务器发出特殊请求并重复失败的请求来重新生成令牌。
由于有多个并发请求产生相同的错误,因此只有在使用以下构造时才应生成令牌:
static final AtomicBoolean isTokenSync = new AtomicBoolean(false);
private static CountDownLatch countDownLatchTokenSync;
if (isTokenSync.compareAndSet(false, true)) {
countDownLatchTokenSync = new CountDownLatch(1);
generateAndSaveToken(...);
isTokenSync.set(false);
countDownLatch.countDown();
}
else {
try {
countDownLatch.await(5, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}
}
}
// repeat the request
基本上第一个线程通过并生成令牌,其他线程等待,直到令牌生成并继续。我的代码是实现这种行为的好方法吗?可以简化吗?
答案 0 :(得分:1)
你可以很好地使用Phaser。它就像一个CyclicBarrier,支持所有到达某个阶段的线程的动态数量的等待方。
static final AtomicBoolean isTokenSync = new AtomicBoolean(false);
private static final Phaser phaser = new Phaser(1);
int phase = phaser.getPhase();
if (isTokenSync.compareAndSet(false, true)) {
generateAndSaveToken(...);
phaser.arrive();
isTokenSync.set(false);
}
else {
try {
phaser.awaitAdvance(phase);
} catch (InterruptedException e) {
}
}
}
每次arrive
,您都会增加相位计数。因此,假设您在phase == 1
处开始方法,到达时将阶段增加到2,并且所有阶段都将小于当前阶段。
答案 1 :(得分:0)
看起来您正在寻找Singleton
。
请参阅here以获得一个好的答案。
这样的事情应该有效。
public static class SingletonToken {
private final String theToken;
private SingletonToken() {
// Do your generateAndSaveToken(...) here.
theToken = "My token";
}
private static class SingletonHolder {
// The constructor is in a static so will be called only once.
private static final SingletonToken instance = new SingletonToken();
}
public static String getToken() {
// By the time the code gets here the instance has been created.
return SingletonHolder.instance.theToken;
}
}
这基本上推迟了与类加载器的同步 - by definition - 线程安全。