我偶然发现一个非常奇怪的问题,我无法理解任何事情.一点点的背景:
我正在尝试运行JavaScriptCore,并将其用作Android应用程序的脚本语言.麻烦的是,主线程上的堆栈大小在较旧的Android版本(类似于16k的API 16)上相当有限.但是,我仍然希望在主线程上调用JS,让它回调请求,并将所有内容都显示为同步.没问题 – 我会鞭打几个通道… khm … SynchronousQueues并反弹来回执行. Here’s what my code looks like.
这很简单 – 每当一些东西叫做延迟 – 它会弹跳到另一个线程,并从那里继续.唯一的问题是,它不起作用.在一个执行Javascript代码的实际用例中,它在某个时候非常可靠地失败,尽管仿真器和不同的设备不在同一个地方. Logcat总是看起来很无害:
I/JavaScriptCore: Lockstep [Main]: Defer
I/JavaScriptCore: Lockstep [Main]: Send EXECUTE_FUNC
I/JavaScriptCore: Lockstep [Background]: Receive EXECUTE_FUNC
I/JavaScriptCore: Lockstep [Background]: Defer
I/JavaScriptCore: Lockstep [Background]: Send EXECUTE_FUNC
然而,第二个EXECUTE从来没有被主要收到,即使投入了.据我所知,这不应该是同步队列.查看线程转储,后台线程在运行循环中等待下一条消息,而main则正坐在incoming.take上.没有其他线程与此进行交互.
在我的一个设备上,我可以设置一个有条件的断点,因为它停止工作的确切时刻,我可以暂停它,就像MAIN正在等待该EXECUTE消息一样.消息是非空的,在这一点上的foregroundQueue是正常的,我可以轮询它有或没有从Android Studio超时,取其大小,无论如何.一旦我跳过所有的操作挂起.
当然,我怀疑JNI shenanigans,但是在Logcat中没有任何内存转储,分段错误或任何警告.
此外,这不仅仅是 – 即使我用一个非常肮脏的等待时间来做:
Message msg = incoming.poll();
if(msg == null) {
Thread.sleep(20);
continue;
}
主要停留在轮询上,后台线程每隔20毫秒就会在另一个队列中快速地拖走.
我试图用一个非常懒惰的阶乘来嵌套一个喜欢睡觉的事实,尽管如此,它没有问题进入200深,整数溢出:
LockstepThread t = new LockstepThread();
int deferredFactoriel(final int n) {
if(n == 0) {
return 1;
}
return n * t.defer(new Functor() {
@Override
public Integer call() {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
return deferredFactoriel(n-1);
}
});
}
@Override
public void onCreate() {
super.onCreate();
for(int i=0; i<200; ++i) {
Log.i("Test", i+"! = " + deferredFactoriel(i));
}
...
什么可能是最奇怪的是,我使用什么同步无关紧要. SynchronizedQueue,ArrayBlockingQueue,LinkedBlocking队列 – 它总是在与同一个线程转储相同的位置失败.地狱,我甚至做了自己的exchanger只是为了看到我不会疯了,它仍然被卡在同样的方式.
那么是的,我完全被骗了.任何想法发生了什么?任何帮助调试这将是非常感谢.