java - Android(在 Scala 中): StackOverflowError depends on when to start a thread?

标签 java android multithreading scala stack-overflow

我有这个简单的 Activity (在 Scala 中,省略了导入):

class TestActivity extends Activity {
  private val TAG = "TestActivity"

  private val mHandler = new Handler {
    override def handleMessage(msg: Message) {
      Log.d(TAG, "handleMessage")
    }
  }

  private val mThread = new Thread {
    override def run {
      mHandler.sendEmptyMessage(0)
      Thread.sleep(10)
      run
    }
  }.start

  override def onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(new TextView(this) {
      setText("hello, world")
    })
  }
}

如您所见,mThread 立即启动,run 被尾递归覆盖,它向 mHandler 发送空消息, hibernate 短时间并再次发送相同的消息。 Activity 开始时,出现此错误:

....
D/TestActivity(28224): handleMessage
D/TestActivity(28224): handleMessage
D/TestActivity(28224): handleMessage
D/TestActivity(28224): handleMessage
I/dalvikvm(28224): threadid=9: stack overflow on call to Landroid/os/MessageQueue;.nativeWake:VI
I/dalvikvm(28224):   method requires 8+20+0=28 bytes, fp is 0x43e33310 (16 left)
I/dalvikvm(28224):   expanding stack end (0x43e33300 to 0x43e33000)
I/dalvikvm(28224): Shrank stack (to 0x43e33300, curFrame is 0x43e35fe0)
W/dalvikvm(28224): threadid=9: thread exiting with uncaught exception (group=0x40015560)

E/AndroidRuntime(28224): FATAL EXCEPTION: Thread-10
E/AndroidRuntime(28224): java.lang.StackOverflowError
E/AndroidRuntime(28224):  at android.os.MessageQueue.enqueueMessage(MessageQueue.java:223)
E/AndroidRuntime(28224):  at android.os.Handler.sendMessageAtTime(Handler.java:457)
E/AndroidRuntime(28224):  at android.os.Handler.sendMessageDelayed(Handler.java:430)
E/AndroidRuntime(28224):  at android.os.Handler.sendEmptyMessageDelayed(Handler.java:394)
E/AndroidRuntime(28224):  at android.os.Handler.sendEmptyMessage(Handler.java:379)
E/AndroidRuntime(28224):  at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:20)
E/AndroidRuntime(28224):  at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:22)
E/AndroidRuntime(28224):  at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:22)
E/AndroidRuntime(28224):  at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:22)
...

现在,如果我不在 mThread 创建后立即启动它,就像这样:

  private val mThread = new Thread {
    override def run {
      mHandler.sendEmptyMessage(0)
      Thread.sleep(10)
      run
    }
  }

并在其他地方触发它,例如,在触摸事件上:

  override def onTouchEvent(event: MotionEvent): Boolean = {
    if (event.getAction == MotionEvent.ACTION_DOWN)
      mThread.start
    true
  }

一切都会好起来的。

我无法解释这个。

最佳答案

所以我做了一些实验,我必须得出结论,如果尾递归覆盖 run 的 Thread 在其创建时的相同表达式中启动,则尾调用优化将失败(还是其他任何可能导致错误的原因?)

差:

class Test {
  val mThread = new Thread {
    override def run {
      println("hello")
      run
    }
  }.start
}

好:

class Test {
  val mThread = new Thread {
    override def run {
      println("hello")
      run
    }
  }
  mThread.start
}

附言我正在运行 Scala 2.9.1,但由于库较小,我使用 2.8.2 进行 Android 开发。

关于java - Android(在 Scala 中): StackOverflowError depends on when to start a thread?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7884482/

相关文章:

java - java中如何检查shell脚本是否执行成功

java - 在应用程序(软件)内构建逻辑的极端可能是什么,即 GMail 附件验证

java - Android Studio 中永远不会调用 onLocationUpdate

linux - 在 Linux 中创建新线程是否复制文件描述符和套接字描述符?

c# - 每秒触发一个事件

java - 无法从 firebase 实时数据库的列表/数组中获取数据

java - 在主线程之外更新UI

android - DJI Phantom 3 相机在 Android Studio 中出现 openCV 问题

java - Android:从字符串值中提取链接

c# - Xamarin IOS WebClient 在线程中执行