线程卡在阻塞队列上.采取没有明显原因
我偶然发现了一个非常奇怪的问题,我无法理解任何事情。先来一点背景故事:
我正在尝试运行JavaScriptCore,并将其用作Android应用程序的脚本语言。麻烦的是,主线程上的堆栈大小在较旧的Android版本上非常有限(在API 16上大约为12k)。但是,我仍然想在主线程上调用JS,让它回调以请求内容,并使所有这些内容看起来都是同步的。没问题 - 我会鞭打几个香奈...嗯......同步排队并来回反弹执行。这是我的代码的样子。
这很简单 - 每次调用延迟时 - 它都会反弹到另一个线程并从那里继续。唯一的问题是,嗯,它不起作用。在执行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 接收,即使看跌期权通过。据我所知,这对于同步队列来说甚至是不可能的。查看线程转储,后台线程在运行循环中等待下一条消息,而 main 则停放在 incoming.take 上。没有其他线程与此交互。
在我的一台设备上,我可以为它停止工作的确切时刻设置一个条件断点,并且可以在MAIN等待该EXPERACT消息时暂停它。该消息是非空的,此时的前景队列正在工作,我可以在有或没有Android Studio超时的情况下轮询它,取其大小,无论什么。一旦我跨过,所有的操作都会挂起。
当然,我怀疑JNI的恶作剧,但是在Logcat中根本没有内存转储,分段错误或任何警告。
此外,这不仅仅是采取 - 即使我用一个非常肮脏的忙碌等待来做:
Message msg = incoming.poll();
if(msg == null) {
Thread.sleep(20);
continue;
}
Main 卡在轮询上,后台线程每隔 20 毫秒就会在另一个队列上快乐地晃动。
我尝试用一个非常懒惰的阶乘嵌套延迟,它喜欢睡很多,尽管它有200个深度,整数溢出,但它没有问题:
LockstepThread t = new LockstepThread();
int deferredFactoriel(final int n) {
if(n == 0) {
return 1;
}
return n * t.defer(new Functor<Integer>() {
@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));
}
...
最奇怪的可能是,我使用什么同步并不重要。SyncedQueue,ArrayBlockingQueue,LinkedBlocking queue - 它总是在同一个位置失败,线程转储完全相同。地狱,我甚至制作了自己的交换器,只是为了看到我不会发疯,它仍然以同样的方式卡住。
所以,是的,我完全被难住了。有什么想法是怎么回事?任何调试此内容的帮助将不胜感激。