Android java.lang.IllegalMonitorStateException:对象在wait()之前未被线程锁定

时间:2013-07-23 13:36:00

标签: java android synchronization notify

我将全局静态对象定义为同步锁。

public static Object ConfirmationSynObj = new Object();

以下函数是我写的,但它抛出了IllegalMonitorStateException。

       synchronized (Config.ConfirmationSynObj) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    //this is a http request
                    appSignInfo = getAPKSignature(context, pkinfo.packageName);
                    Config.ConfirmationSynObj.notify();
                }
            }).start();
            try {
                Config.ConfirmationSynObj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (appSignInfo == null) {
                return ret;
            }
        }

有人知道如何锁定对象或函数以防止并发吗?

4 个答案:

答案 0 :(得分:8)

wait / notify的常见替代品是CountDownLatch。 (也可以从java.util.concurrent开始,但Semaphore的反向工作 - 请参阅汤姆的答案)

您将其初始化为所需的步骤数,已完成倒计时的线程以及其他某些位置等待倒计时达到0。

void doFoo() {
    final CountDownLatch latch = new CountDownLatch(1);
    new Thread(new Runnable() {

        @Override
        public void run() {
            //this is a http request
            appSignInfo = getAPKSignature(context, pkinfo.packageName);
            latch.countDown();
        }
    }).start();
    try {
        latch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    if (appSignInfo == null) {
        return ret;
    }
}

但是你在那里写的代码可以简化为

void doFoo() {
    return getAPKSignature(context, pkinfo.packageName);
}

你开始第二个线程做某事,你所做的就是等待。如果在该任务运行时无事可做,请不要创建额外的线程。结果是一样的。

如果您尝试在UI线程之外执行HTTP请求,因为您获得了NetworkOnMainThreadExcpeption,则必须采用不同的方式。虽然Android不会长时间阻止代码检测到您的代码,但它仍然存在。例如,使用AsyncTask。

答案 1 :(得分:5)

@Kayaman说得对,据我所知,如果我可以谦虚地建议:java.util.concurrent可以节省你很多时间!

我使用的是semaphore

来自文档:"每个acquire()都会在必要时阻止,直到获得许可证为止,然后接受它。"。

但是还有其他选择 - 我强烈建议在可能的情况下使用它,因为你应该避免像你的情况那样陷阱。

        Semaphore semaphore = new Semaphore(0);
        new Thread(new Runnable() {

            @Override
            public void run() {
                //this is a http request
                appSignInfo = getAPKSignature(context, pkinfo.packageName);
                semaphore.release();
            }
        }).start();
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

答案 2 :(得分:2)

您可能正在同步块中创建并启动线程,但当线程进入Config.ConfirmationSynObj.notify();时,您会注意到没有同步。

您需要在run()中添加一个synchronized块。

答案 3 :(得分:2)

 new Thread(new Runnable() {

            @Override
            public void run() {

上面的帖子没有对ConfirmationSynObj对象拥有锁定因此抛出IllegalMonitorStateException

run方法

中使用一个以上的同步块
           @Override
            public void run() {
            synchronized (Config.ConfirmationSynObj) {
                //this is a http request
                appSignInfo = getAPKSignature(context, pkinfo.packageName);
                Config.ConfirmationSynObj.notify();
               }
            }