我将全局静态对象定义为同步锁。
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; } }
有谁知道如何锁定对象或函数以防止并发?
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); }
你开始第二个线程做某事,你在那段时间所做的就是等待。 如果在该任务运行时无事可做,请不要创建额外的线程。 结果是一样的。
如果您尝试在UI线程之外执行HTTP请求,因为您获得了NetworkOnMainThreadExcpeption
,则必须以不同方式执行此操作。 虽然Android不会长时间阻止代码检测到您的代码,但它仍然存在。 例如,使用AsyncTask。
@Kayaman说的正确,据我所知,但是如果我可能谦卑地建议: java.util.concurrent
可以节省你很多时间!
我在那里使用的是一个信号量 。
从文档:“每个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(); }
您可能正在同步块中创建并启动线程,但是当线程进入Config.ConfirmationSynObj.notify();
你会注意到没有同步。
您需要在run()中添加一个synchronized块。
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(); } }