【问题标题】:CountDownLatch in Android locking threadAndroid锁定线程中的CountDownLatch
【发布时间】:2016-08-01 08:52:09
【问题描述】:

我刚刚开始在我的 Android 应用中使用 CountDownLatch。目前我正在尝试向我的 api 发出两个Volley 请求,并等到数据被检索和存储后再继续执行线程。

这是我的代码示例:

    // new CountDownLatch for 2 requests
    final CountDownLatch allDoneSignal = new CountDownLatch(2);

    transactions.getResourcesForRealm(Contact.class, "", new ICallBack<Contact>() {
        @Override
        public void onSuccess(ArrayList<Contact> resources, String resourceId) {
            transactions.createRealmObject(resources, Contact.class);

            allDoneSignal.countDown();
        }

        @Override
        public void onFail(ArrayList<Contact> resources) {

        }
    });

    transactions.getResourcesForRealm(Meeting.class, "", new ICallBack<Meeting>() {
        @Override
        public void onSuccess(ArrayList<Meeting> resources, String resourceId) {
            transactions.createRealmObject(resources, Meeting.class);

            allDoneSignal.countDown();
        }

        @Override
        public void onFail(ArrayList<Meeting> resources) {

        }
    });

    try {
        allDoneSignal.await();
        // continue executing code
        // ...
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

问题在于它似乎没有“完成”倒计时,因此由于闩锁从未释放而冻结。我已经确认 API 请求正在工作并且onSuccess 回调成功命中,但线程挂起。

更新 我刚刚注意到,将CountDownLatch 设置为0,它会命中onSuccess,但是当我将它设置为大于0 的任何值时,它就会冻结并且永远不会调用onSuccess。线程似乎很时髦。

【问题讨论】:

  • 我可能错了,但对于线程和值相关的问题,请检查Volatile variable 概念。
  • 这应该可以按预期工作 - 您可以在调用 countDown 之前记录一些内容以确保确实调用了该方法吗?
  • @PradeepKumarKushwaha 这里不需要 volatile,latch 已经提供了足够的同步保证。
  • 我会尝试Log.wtf这个...
  • 您还说“2 个请求的新倒计时” - 可能会仔细检查三个位置的 allDoneSignal 变量是否相同(如果代码与您在单个方法中发布的完全一样,那么它显然是)...

标签: java android multithreading android-volley countdownlatch


【解决方案1】:

您的代码太容易出错,您需要在 finally 块中调用 countDown() 并在 onFail 中调用它,否则如果失败,您的应用程序将永远冻结。所以你的代码应该是这样的:

transactions.getResourcesForRealm(Contact.class, "", new ICallBack<Contact>() {
    @Override
    public void onSuccess(ArrayList<Contact> resources, String resourceId) {
        try {
            transactions.createRealmObject(resources, Contact.class);
        } finally {
            allDoneSignal.countDown();
        }
    }

    @Override
    public void onFail(ArrayList<Contact> resources) {
        allDoneSignal.countDown();
    }
});

transactions.getResourcesForRealm(Meeting.class, "", new ICallBack<Meeting>() {
    @Override
    public void onSuccess(ArrayList<Meeting> resources, String resourceId) {
        try {
            transactions.createRealmObject(resources, Meeting.class);
        } finally {
            allDoneSignal.countDown();
        }
    }

    @Override
    public void onFail(ArrayList<Meeting> resources) {
        allDoneSignal.countDown();
    }
});

【讨论】:

  • 虽然一般来说这是一个很好的建议,但它并不能回答问题,这个问题非常糟糕,需要假设您不必这样做。
  • @SleimanJneidi 是的,我知道,但我们都知道 CountDownLatch 运行良好,所以如果程序冻结,那是因为 countDown() 由于某种原因没有按预期调用两次,所以我只是提供一种方法来确保即使在失败的情况下也会调用它
  • 感谢良好的错误处理,我已经实现了这个,我正在试图弄清楚为什么它没有命中countDown()
  • @barnacle.m 相信是调用线程调用了onSuccess,尝试打印Thread.currentThread()的值
  • 我尝试将锁存器作为异步请求的参数传入并在新线程中倒计时。它仍然挂起。
【解决方案2】:

对不起,回答迟了,但如果它仍然对任何人有帮助:

您需要在单独的线程中执行“.await”,因为它会阻塞当前线程。

例子:

final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
new Thread(new Runnable() {
    @Override
    public void run() {
        allDoneSignal.await();
        mainThreadHandler.post(new Runnable() {
            doSomethingWhenAllDone();
        });
}
}).start()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    相关资源
    最近更新 更多