You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为lazy val定义的AccessToken实现可刷新能力并保障线程安全

实现线程安全且支持自动刷新的Token方案

原有lazy委托仅支持单次初始化,无法满足定期刷新的需求,你可以通过双重校验锁+缓存过期时间的方案改造,对外仍然保持val的调用方式不变:

object MyObj {
    // 缓存Token和对应的过期时间戳(毫秒)
    private var tokenCache: Pair<String, Long>? = null
    // 锁对象,控制并发刷新
    private val refreshLock = Any()
    // 提前5分钟刷新,规避临界期请求失败问题
    private const val ADVANCE_REFRESH_MS = 5 * 60 * 1000L
    // 服务端下发的Token有效期1小时
    private const val TOKEN_VALID_MS = 3600 * 1000L

    val accessToken: String
        get() {
            val currentTime = System.currentTimeMillis()
            // 第一层校验:无锁判断缓存是否有效,绝大多数请求都走这个分支
            val currentCache = tokenCache
            if (currentCache != null && currentTime < currentCache.second - ADVANCE_REFRESH_MS) {
                return currentCache.first
            }
            // 缓存过期,加锁进入刷新逻辑
            return synchronized(refreshLock) {
                // 第二层校验:加锁后再次判断,避免多线程排队时已经被其他线程刷新过
                val latestCache = tokenCache
                if (latestCache != null && currentTime < latestCache.second - ADVANCE_REFRESH_MS) {
                    latestCache.first
                } else {
                    val newToken = getAccessTokenFromHttpApi(username, password)
                    val newExpireTime = currentTime + TOKEN_VALID_MS
                    tokenCache = newToken to newExpireTime
                    newToken
                }
            }
        }
}

关键特性说明

  • 线程安全:同一时间最多只有一个线程执行Token刷新操作,双重校验机制保证未过期时的读操作完全无锁,性能损耗极低
  • 平滑刷新:提前5分钟触发刷新,避免Token刚好到有效期临界点时请求被服务端拒绝
  • 兼容原有逻辑:对外暴露的仍然是只读val属性,原有调用accessToken的代码不需要做任何修改

可选优化点

如果getAccessTokenFromHttpApi接口会返回准确的过期时长(比如接口返回expires_in字段),可以直接用接口返回的数值替换代码中硬编码的TOKEN_VALID_MS,时效性更准确。
如果遇到网络波动导致刷新请求失败,可以增加容错逻辑:只要旧Token还未到真正的过期时间,就暂时返回旧Token,避免业务直接报错。

内容的提问来源于stack exchange,提问作者k314159

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 16:12:03