java - 取消长轮询循环的并发问题

标签 java android multithreading synchronization

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

我正在使用客户端库(我觉得它写得不好)与实时聊天服务器进行交互,该服务器使用 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)

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

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

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

或者按照下面的建议,我可以使用中断来达到同样的目的

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

谢谢

最佳答案

我买了Java Concurrency in Practice作为这个问题的结果,发现他们在第 7 章:取消和关闭中讨论了一个非常像这个的问题,可以用引述来总结

Interruption is usually the most successful way to implement cancellation

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

我还按照建议将 boolean 值 unsubscribe 字段设置为 volatile,这是我之前应该做的 - 然而,仅此一项并不能解决问题

关于java - 取消长轮询循环的并发问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14214672/

相关文章:

java - 比较一对 3 个变量的数学方法

Java:A类中B类的实例,其中B类使用A类中声明的变量

android - GC 运行过于频繁

android - 为什么gradle android插件不为intellij idea模块生成依赖项

c++ - boost 线程禁用

java - 如何在方法内部创建方法并捕获java中方法上面的函数名称,从而使

java - Lucene:跨查询比较结果

android - Sqlite自增列问题

c++ - std::promise set_value 和线程安全

C++,如何在进程或线程之间共享数据