java - 如何简化尴尬的并发代码?

标签 java android multithreading concurrency locking

基本上这段代码会执行http请求,如果http请求超时,它会重置wifi连接(有时必须这样做,事情就是这样,我也可以是其他非android相关的东西,而不是“重置 wifi 连接”)。

必须考虑以下特殊情况:

  • 如果 1 个或多个线程当前正在执行 http 请求,则不允许另一个线程重置 wifi 连接
  • 如果当前已经有 1 个线程正在重置 wifi 连接,并且另一个线程即将重置 wifi 连接,则直接发送后一个线程以重试 http 请求(当前一个线程完成重置 wifi 时)
  • 当前正在重置 wifi 连接时不要执行 http 请求
  • => 一次只有1个线程可以修复wifi连接,但多个线程可以同时发起http请求

这让我头疼。

这是到目前为止我的代码。我可以改进什么?

static int requestsActive = 0;
protected int requestTry = 0;
static final int maxTrys = 2;
static final ReentrantLock wifiLock = new ReentrantLock();

public void evaluate() throws Exception {
try {
    requestTry++;
    while (wifiLock.isLocked()) // no not start new http request while wifi is being fixed
        Thread.sleep(400);
    requestsActive++; //increment so that another thread that wants to fix wifi knows it has to wait
    response = httpClient.execute(requestBase);
    requestsActive--; // when == 0 wifi can be fixed if it needs to
} catch (ConnectTimeoutException e) {
    requestsActive--; //same as above (for exception case)
    if (requestTry == maxTrys)
        throw new ConnectTimeoutException("maxTrys reached");
    if (!wifiLock.tryLock()) //another thread is currently fixing wifi, no need to do it myself
        evaluate(); // ...so start a new http request
    while (requestsActive > 0) // wait until no more threads are in the http request section above
        Thread.sleep(400);
    WifiManager wifiMan = (WifiManager) App.getContext().getSystemService(Context.WIFI_SERVICE);
    resetWifi(wifiMan); //reset android wifi, nothing special
    wifiLock.unlock();
    evaluate();
}

最佳答案

不幸的是,我不能保证这会起作用,因为我没有安装 Android 模拟器并很快将其组合在一起。希望它至少作为一个构建的概念对您有所帮助。基本上,它使用信号量来允许一次尝试有限数量的请求,当连接超时时,它将获取信号量的所有许可,这将阻止在 wifi 重置时发出任何新请求。这利用了 Java 代码库中已有的并发代码,因此您不必自己重新实现任何代码。

您可以查看信号量的 JavaDoc here .

static final int MAX_CONCURRENT_REQUESTS = 10;
static final Semaphore httpRequestsLock = new Semaphore(MAX_CONCURRENT_REQUESTS, true);

public void evaluate() throws Exception {
    Foo requestBase = null;
    HttpClient httpClient = new HttpClient();

    httpRequestsLock.acquire();
    try{
        response = httpClient.execute(requestBase);
    }
    catch (ConnectTimeoutException e) {
        httpRequestsLock.release();
        httpRequestsLock.acquire(MAX_CONCURRENT_REQUESTS); // Blocks until all current requests are done
        WifiManager wifiMan = (WifiManager) App.getContext().getSystemService(Context.WIFI_SERVICE);
        resetWifi(wifiMan); //reset android wifi, nothing special
        httpRequestsLock.release(MAX_CONCURRENT_REQUESTS);
        evaluate();
    }
}

关于java - 如何简化尴尬的并发代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14186636/

相关文章:

java - 为什么这个 Java 静态字段为空?

java - 如何将米转换为英里,并以英尺和英寸为单位给出余数?

c# - Xamarin 使用 FontAwesome 创建自定义按钮

Android编译库错误

java - 为 apache httpcomponents 使用的线程命名

java - 为什么我的线程不循环?

java - 如何在运行时以编程方式更改默认服务器 Play + Ebean

安卓NDK : Infinite Loop Not Being Called Infinitely

javascript - #onmessage 和 #postmessage 如何在主线程和 HTML5 的 webworkers 之间进行通信?

java - 查找文档相似性的最佳方法