【问题标题】:Android java.lang.IllegalMonitorStateException: object not locked by thread before wait()Android java.lang.IllegalMonitorStateException:对象未在等待()之前被线程锁定
【发布时间】:2013-07-23 13:36:00
【问题描述】:

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

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;
            }
        }

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

【问题讨论】:

  • 请遵循 Java 命名约定。

标签: java android synchronization notify


【解决方案1】:

wait/notify 的常见替代品是 CountDownLatch。 (也来自java.util.concurrent,但工作方式与Semaphore相反 - 请参阅Tom的回答)

您将其初始化为所需的步数,已完成倒计时的线程和其他一些地方等待倒计时达到 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);
}

您启动第二个线程来做某事,而您在那段时间所做的就是等待。如果在该任务运行时无事可做,请不要创建额外的线程。结果是一样的。

如果您因为得到NetworkOnMainThreadExcpeption 而尝试在 UI 线程之外执行 HTTP 请求,则必须以不同的方式执行。虽然 Android 不会像长时间阻塞代码那样检测到您的代码,但它仍然是。以 AsyncTask 为例。

【讨论】:

  • @user924 你的评论有什么意义?是的,它们是不同的,但是闩锁将满足等待/通知的一部分情况。
【解决方案2】:

@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();
        }

【讨论】:

    【解决方案3】:
     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();
                   }
                }
    

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 2012-05-24
        • 2014-12-22
        • 1970-01-01
        • 2017-03-17
        • 2018-11-30
        • 1970-01-01
        • 1970-01-01
        • 2018-11-02
        • 1970-01-01
        相关资源
        最近更新 更多