1.微信規定token週期爲7200,所以在2小時內需要再次獲取,那麼問題來了,假如線程程序更新週期爲7100,在7100前一秒來了1000個請求(假設),這1000個請求在這一時刻獲取了token(老的),又假設處理1000個請求所需時間大於1秒,定時獲取token線程去更新token,這時1000個請求還未處理完的請求token就全部失效了,想要表達的就是你處理請求的過程中token發生變化,而請求中的token還沒有更新。
1.1解決思路,在處理請求時加鎖,在未處理完畢請求時,不會更新token。更新token時不會處理請求,一直阻塞到更新token完成,纔會去處理請求。考慮阻塞時間可以自己設定token的更新週期,保證token可用。
1.1.1 可用用線程synchronize,但是這樣就會有效率問題,獲取token時和更新token加synchronize,問題時多線程獲取token是一個一個執行的,降低了多線程的優勢。
1.1.2 考慮用讀寫鎖,這樣多線程可以同時讀取token,讀取token時不可以更新token。更新token時,不可以獲取token。
2創建讀寫鎖,爲token加鎖
public class TokenWRLock {
//微信token信息,當超時對其加讀寫,保證微信業務正常
private static String accessToken = null;
//創建一個讀寫鎖
private static ReadWriteLock lock = new ReentrantReadWriteLock();
/*
*
*/
public static void setToken(String token) {
try {
lock.writeLock().lock();
//Thread.sleep(1000);
accessToken = token;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
/*
* 獲取token加鎖
*/
public static String getTokenWithLock() throws Exception {
lock.readLock().lock();
//System.out.println("@@@@@"+new Date().getSeconds());
return accessToken;
//fun();
//lock.readLock().unlock();
}
/*
* 釋放token鎖
*/
public static void unLockToken() throws Exception {
//lock.readLock().lock();
//System.out.println("@@@@@"+new Date().getSeconds());
//fun();
lock.readLock().unlock();
}}
上面用到ReadWriteLock,這是個好東西。相比sync,它的優勢就是多線程執行,不會排隊。
3.創建定時獲取token線程
public class TokenScheduleTask extends Thread {
Logger logger = Logger.getLogger(NotifyScheduleTask.class);
public void initMethod() {
this.start();
}
@Override
public void run() {
try {
while(true) {
//獲取token
this.tokenTask(0);
Thread.sleep(7100 * 1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//定時獲取token
public void tokenTask(int retry) throws InterruptedException {
try {
if(retry >= 3) {
logger.error("獲取token異常重試次數以達上線");
return;
}
String token = WeiChatUtils.getAccessToken().getAccessToken();
TokenWRLock.setToken(token);
} catch (Exception e) {
retry++;
logger.error("獲取token異常:",e);
Thread.sleep(1*1000);
this.tokenTask(retry);
}
}
}
收工