【问题标题】:Thread getting stuck on BlockingQueue.take for no apparent reason线程无缘无故卡在 BlockingQueue.take
【发布时间】:2016-08-22 13:49:02
【问题描述】:

我偶然发现了一个我无法理解的非常奇怪的问题。先说一点背景故事:

我正在尝试运行 JavaScriptCore 并将其用作 Android 应用程序的某种脚本语言。问题是,主线程上的堆栈大小在较旧的 Android 版本上非常有限(类似于 API 16 上的 12k)。但是,我仍然想在主线程上调用 JS,让它回调以请求事物并让所有这些看起来是同步的。没问题 - 我会抽出几个 channe...khm... SynchronousQueues 并来回反弹执行。 Here's what my code looks like.

这很简单 - 每次调用 defer - 它都会反弹到另一个线程并从那里继续。唯一的问题是,它不起作用。在执行 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 接收到,即使 put 通过了。据我了解,同步队列甚至都不可能做到这一点。查看线程转储,后台线程正在运行循环中等待下一条消息,而主线程则停在 incoming.take 上。没有其他线程与之交互。

在我的一个设备上,我可以在它停止工作的确切时刻设置一个条件断点,并且我可以在 MAIN 等待那个 EXECUTE 消息时暂停它。该消息是非空的,此时的foregroundQueue 正在工作,我可以从Android Studio 轮询它,无论是否超时,取它的大小等等。一旦我跨过所有操作,就会挂起。

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

此外,这不仅仅是采取 - 即使我在非常肮脏的忙碌等待中这样做:

Message msg = incoming.poll();
if(msg == null) {
 Thread.sleep(20);
 continue;
}

Main 卡在 poll 上,后台线程每 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,只是为了确保我不会发疯,但它仍然以同样的方式卡住。

所以是的,我完全被难住了。有什么想法吗?任何有关调试的帮助将不胜感激。

【问题讨论】:

  • 请展示一个示例 Functor,我怀疑您的 Functor 对 defer/runLoop 的嵌套调用错误,导致死锁。
  • 正如@glee8e 所说:这看起来像是Functor 中的代码有问题。您的示例代码没有显示如何从后台线程调用 defer,但您的日志跟踪显示了这种情况。

标签: java android concurrency android-ndk


【解决方案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());

            }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-23
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    • 2017-04-11
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    相关资源
    最近更新 更多