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

Ivo*_*lov 17 java concurrency android android-ndk

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

我正在尝试运行JavaScriptCore并将其用作Android应用程序的各种脚本语言.麻烦的是,主要线程上的堆栈大小在较旧的Android版本上非常有限(类似于API 16上的12k).但是,我仍然希望在主线程上调用JS,让它回调请求事情并使所有这些看起来都是同步的.没问题 - 我会甩掉几个通道... khm ... SynchronousQueues并反复弹跳执行.这是我的代码的样子.

它非常简单 - 每次调用延迟时 - 它会反弹到另一个线程并从那里继续.唯一的问题是,它不起作用.在执行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
Run Code Online (Sandbox Code Playgroud)

然而,第二次EXECUTE永远不会被主要接收,即使看跌.据我所知,对于同步队列来说甚至都不可能.查看线程转储,后台线程正在运行循环中等待下一条消息,而main正在停靠在incoming.take上.没有其他线程与此交互.

在我的一个设备上,我可以设置一个条件断点,以确保它停止工作的确切时刻,我可以暂停它,就像MAIN正在等待那个EXECUTE消息一样.消息是非空的,此时的foregroundQueue正在工作,我可以使用或不使用Android Studio的超时轮询它,取其大小,无论如何.我一踏完所有操作就挂了.

当然,我怀疑是JNI恶作剧,但在Logcat中没有内存转储,分段错误或任何警告.

此外,它不仅仅是采取 - 即使我做了一个非常肮脏的繁忙等待:

Message msg = incoming.poll();
if(msg == null) {
 Thread.sleep(20);
 continue;
}
Run Code Online (Sandbox Code Playgroud)

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));
  }

...
Run Code Online (Sandbox Code Playgroud)

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

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

小智 1

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

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());

            }
Run Code Online (Sandbox Code Playgroud)