微信開發定時獲取token,保證線程安全,高可用

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);
        }
    }
}

收工


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章