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

时间:2013-01-08 12:11:27

标签: 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)

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

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

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

如下所示,我可以将中断用于相同的目的

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

谢谢

2 个答案:

答案 0 :(得分:3)

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

  

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

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

我也按照我之前应该做的建议将布尔unsubscribe字段设置为volatile - 但这本身就没有解决问题

答案 1 :(得分:2)

1)将取消订阅设为易失性

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