线程卡在BlockingQueue.take上没有明显的原因

时间:2016-04-28 01:41:57

标签: java android concurrency android-ndk

我偶然发现了一个非常奇怪的问题,我无法理解任何问题。首先是一些背景故事:

我试图运行JavaScriptCore并将其用作Android应用程序的各种脚本语言。麻烦的是,主要线程上的堆栈大小在较旧的Android版本上非常有限(类似于API 16上的12k)。但是,我仍然希望在主线程上调用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的恶作剧,但在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<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));
  }

...

最奇怪的是,我使用的同步并不重要。 SynchronizedQueue,ArrayBlockingQueue,LinkedBlocking队列 - 它始终在完全相同的线程转储的同一位置失败。天哪,我甚至自己创造了exchanger只是为了看到我不会疯狂而且它仍然以同样的方式陷入困境。

所以是的,我完全被难倒了。有什么想法会发生什么?任何有关调试的帮助都将非常感激。

1 个答案:

答案 0 :(得分:0)

  

你为什么要使用线程?线程也有替代品。尝试   使用这样:可能是它的作品

static Timer timer;
    private TimerTask timerTask;


try {
                timer = new Timer();
                    timerTask = new TimerTask() {

                        @Override
                        public void run() {
                        }
                        }
                    };
                    timer.schedule(timerTask, 4000);
                } else {
                     timer.cancel();
                    // timer.purge();
                    MainHomeActivity.appendLogSocket("UPDATE RECEIVER : ",
                            "TIMER STOPED");

                }
            } catch (Exception e) {
Log.e(      "Socket update receiever error: ", e.toString());

            }