11

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

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

4 回答 4

10

wait/的常见替代品notifyCountDownLatch。(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。

于 2013-07-23T14:07:31.680 回答
5

@Kayaman 说得对,据我所知,但是如果我可以谦虚地建议:java.util.concurrent可以为您节省大量时间!

我在那里使用的是semaphore

来自文档:“如果有必要,每个获取()都会阻止,直到获得许可,然后再接受它。”。

但也有其他选择——我强烈建议尽可能使用它,因为你应该避免像你的情况那样出现很多坑。

        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();
        }
于 2013-07-23T13:39:49.940 回答
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();
               }
            }
于 2013-07-23T13:44:38.033 回答
2

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

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

于 2013-07-23T13:38:32.893 回答