允许一个线程更新值(刷新身份验证令牌),其他线程等待并跳过关键部分

我正在从多个线程向多个目标发送HTTP请求。这些请求需要授权。我只有一个授权服务器,从那里可以获取授权令牌。

因此,当授权令牌到期时(即HTTP响应状态401),我希望其中一个线程去刷新令牌,而其他线程在等待。刷新令牌后,所有线程应继续发送请求,而无需再次刷新令牌。

这是我的实现方式

RAISEERROR
type httpSenderAgent struct {
    // irrelevant members omited
    ...
    client *http.Client
    tokenState int // (valid = 1,expired = 0)
    token string
    cond sync.Cond
}
func (a *httpSenderAgent) send(url string,body interface{},retrycount int) error {

    if retrycount >= MAX_AUTH_RETRY {
        return errors.New("Max retry exceeded")
    }

    buf := &bytes.Buffer{}
    json.NewEncoder(buf).Encode(body)
    req,err := http.NewRequest("POST",url,buf)
    if err != nil {
        return err
    }

    req.Header.Add("Content-Type","application/json; charset=utf-8")
    req.Header.Set("Authorization","Bearer "+a.token)

    res,err := a.client.Do(req)
    if err != nil {
        return err
    }

    defer res.Body.Close()

    if res.StatusCode == http.StatusUnauthorized {
        a.refreshAuthToken()
        return a.send(url,body,retrycount + 1)
    }

    if res.StatusCode < 200 || res.StatusCode > 299 {
        return errors.New(http.StatusText(res.StatusCode))
    }

    return nil
}

但是,在以下情况下会出现问题:

比方说,第一个线程获得401响应,它使func (a *httpSenderAgent) refreshAuthToken() { // lock section 1 a.cond.L.Lock() if a.tokenState == valid { a.tokenState = expired go func() { // getauthToken() is a http call to auth server tkn := a.getauthToken() // lock section 2 a.cond.L.Lock() a.token = tkn a.tokenState = valid a.cond.L.Unlock() a.cond.Broadcast() }() } for a.tokenState != valid { a.cond.Wait() } a.cond.L.Unlock() } 过期,启动goroutine来获取令牌,并等待令牌有效,与此同时,另一个线程获得401并调用{{1} }。此时,令牌提取线程进入tokenState。因此,第二个线程无法输入refreshAuthToken(),它等待互斥锁被解锁。当令牌获取线程将lock section 2更新为有效并解锁互斥锁时,第二个线程将锁定该互斥锁并发现该令牌有效。因此,它将重复整个令牌获取过程。

我已经检出了标题为Java- Allow one thread to update a value,others to wait and skip critical section的SO问题。但是,答案并不涵盖我的用例。

那么,如何更改此方法以仅获取一次身份验证令牌,直到再次过期?我应该使用什么同步原语来实现此目的?

zlzlyw 回答:允许一个线程更新值(刷新身份验证令牌),其他线程等待并跳过关键部分

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/2789084.html

大家都在问