JS->Applet->JS导致死锁问题解决过程

 最近两天被一个非常棘手的问题缠住了,大致是这样的。为了和别的应用系统集成,我把WebGIS的客户端拆分了一下,Toolbar和Toc(图层树)分离出来用html实现,地图显示部分还是用Applet,用JavaScript来实现他们之间的交互。为了使html的Toc和Applet内部图层状态保持一致,我用回调机制来同步。也就是因为回调导致该页面如果放在一个ModalDialog中就会导致死锁,IE没有响应。而在普通的窗口中一切正常。
        Applet运行在IE中不好直接调试,也许我没有找到调试的办法。一旦死锁,Java Console也不再刷新,看不到任何东西,通常使用的写日志的方法不再起作用。怎么办呢,一开始我真的没把握能解决这个问题,但是没办法赶鸭子上架也得上。
        首先我观察死锁出现的规律,同事和我说不让它自动定位就不会死,但是我发现去掉自动定位手动定位也一样死。我所知道的Modal于Modaless的区别是不允许激活别的窗口,不能弹出非模态窗口。我一直想办法验证是否因为非模态窗口的原因,因为Toc在div元素中,div元素比较特别,会不会是独立窗口,因为只要操作一下Toc就会死。
         写到这里我想起了一句话“大胆假设,小心求证”。于是我逐一验证我的一系列假设,div上放一个按钮,Applet的一个回调方法去操作该按钮,没有问题。与div一点关系都没有,此外toc可以直接放在一个td元素中,还是照死不误。经过大量的猜测--验证,我终于找出了规律。纯粹的JS->Applet(Toolbar上的按钮)或者Applet->JS都可以,但是如果是JS->Applet->JS就会导致死锁。问题原因找出来,解决这个问题远非易事。
         Modal Dialog只允许一个线程执行,Applet很明显在另外的线程中执行,在JVM中运行,JS调用Applet的方法必须等Applet方法返回来才能执行新的函数或语句,模态对话框中不允许中途被打断去执行别的函数。但是回调不能不用,否则没法实现状态同步。
        粗略想了想,为了让Applet方法尽快返回,一个办法是创建另一个线程来执行回调。说干就干,真的不会死了,但是状态没有同步,看Java Console中消息Applet调用JS的方法被阻塞了,一直到窗口关闭的时候才返回。不能用另外的线程来执行回调,真是变态。这样的话只能用运行Applet的线程来执行,但是该线程会堵塞,几乎走入绝境了。
       我想到了定时器,而且是javax.swing.Timer。JS调用的Applet方法只是把定时器启动起来,把调用方法和参数放到List中就返回了。延迟一段时间后Applet再调用JS,此时JS对Applet的调用已经结束。效果不错!正要给同事演示,临时把延迟改为50ms,它又让我难堪了,还是死锁。后来把时间延长至1s,比较稳定了,但是必须保证在1s之内JS对Applet的调用必须结束,否则还是会出现死锁。还有所有的回调均延迟没有必要,反应很迟钝,从Applet到JS的调用根本没必要延迟的。进一步改进,设置状态变量,如果JS调用延迟,Applet发起的调用不延迟,这样JS脚本不需要作任何修改,只要更新Applet就可以解决问题,而对Applet的是自动下载的。
        这样结果还是比较令人满意的,做开发和搞科研很多地方是相似的,比如说大胆假设,小心求证。另外一个人的经验体现在根据问题症状作出的假设,对这方面的问题越了解,假设越接近事实,很快找到解决办法,反之折腾了半天不知道从何下手。用最简单最快的手段验证你的假设,根据新的观察修改你的模型。

你可能感兴趣的:(JS->Applet->JS导致死锁问题解决过程)