【问题标题】:Concurrency issue for cancellation of long-poll loop取消长轮询循环的并发问题
【发布时间】:2013-01-08 12:11:27
【问题描述】:

我有一个问题,我希望通过写这个问题来解决,但如果没有,我会发帖看看是否有人可以提供帮助。

我正在使用客户端库(我觉得写得不好)与实时聊天服务器交互,该服务器使用 COMET 风格的 HTTP 长轮询。我在某些情况下无法取消长轮询,我怀疑我可能需要添加一些并发处理代码,但由于以下原因,我发现很难找到最好的方法。

订阅代码(启动长轮询)作为一个大循环实现,如下

doLongPoll()
{
    while(true)
    }
        //IF channel field boolean unsubscribe == TRUE, if so BREAK;
        //perform GET request (and store channel HTTPClient used for this call)
        //remove HTTPClient used for this call
        //IF channel field boolean unsubscribe == true, if so BREAK;
        //IF connection problem sleep(1500) then CONTINUE
        //post received data to listeners
    }
}

取消订阅调用(将调用另一个线程)

unsubscribe()
{
    //set channel field boolean unsubscribe == FALSE
    //get channel HTTPClient and shutdown
}

我已经隔离了操作交错的问题案例。对我来说,这似乎是代码是多线程的并且客户端代码不是线程安全的结果。 httpClient 的管理不善和不重复使用也无济于事。

我遇到的问题之一是取消订阅调用不会阻止下一个 getRequest 的发生。

THREAD 1 (polling)                      THREAD 2
--------                                --------
do unsubscribe check (pass)
                                        unsubscribe called
                                        set unsubscribe = true
                                        check if httpClient saved (none)
perform getRequest (save HttpClient first)

我想知道人们认为解决这个问题的最佳方法是什么(时间也有限,所以我不能重写太多代码!)

要解决这个问题,我想我可以使用 同步块 从线程 1 的第一次取消订阅检查到 httpClient 在实际获取请求执行和同步之前保存unsubscribe 方法使用相同的锁。目前这是不切实际的,因为提到的第一个同步块将在一个方法调用中开始并在方法调用链的下游完成(由于 lib 的编写方式)——这感觉非常错误,因此需要进行一些重构。

或者我可以只为每个频道创建一个httpClient,而不是每个请求,然后它可能总是被关闭,我可能会忽略同步(我认为)。

或者按照下面的建议,我可以将 中断 用于相同目的

欢迎任何建议 - 如果我有任何进展,我会编辑!

谢谢

【问题讨论】:

  • 1.布尔值是易失性的吗? 2. 使用中断代替布尔值不是更容易吗?
  • 1.不,但取消订阅调用是同步的,因此线程本地值不应该有问题。 2. 可能,我昨天正在考虑这个问题,但想看看这里有什么建议——我可以走那条路。
  • "取消订阅调用已同步" => 写入 unsubscribe = true; 位于同步块中。但是在doLongPoll 中读取if (unsubscribe) break; 怎么样?
  • if (unsubscribe) break; 中的 doLongPoll 不在同步块中 否 - 我不认为将这条线单独放在同步块中会产生任何影响,因为当写入同步块退出时它会重新-sync 任何线程局部变量。另外,我认为仅此一项并不能阻止上述问题?
  • 要正确共享变量,您需要同步读取和写入(例如,在布尔值的情况下,可以通过使变量变为易失性来完成)。但这并不能解决您的交错问题。

标签: java android multithreading synchronization


【解决方案1】:

由于这个问题我买了Java Concurrency in Practice,发现他们在第7章:取消和关闭中讨论了一个非常相似的问题,可以通过引用来概括

中断通常是最成功的实施方式 取消

由于 HttpClient 阻塞了不支持中断的套接字 IO,所以我有两种方法。我分配了我的httpClient,在实际的httpClient.execute() 调用之前检查中断,并在我的unsubscribe() 方法中中断线程,然后调用httpClient.getConnectionManager().shutdown();。这似乎解决了我的问题,并且是一个非常简单的更改。没有更多的交错问题!

我还将布尔值 unsubscribe 字段设置为 volatile,正如我之前应该做的那样 - 仅此一项并不能解决问题

【讨论】:

    【解决方案2】:

    1) 将取消订阅设置为 volatile

    2) 为了获得更大的保证,保护访问(读/写)以取消订阅,例如,信号量

    【讨论】:

    • 感谢您的回答,但这与@assylias 的说法相同,并不能真正解决问题
    猜你喜欢
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    • 2013-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多