【发布时间】:2013-05-06 20:08:18
【问题描述】:
我正在对 Java 中的事件回调处理框架进行压力测试,该框架在可能的情况下大量使用并发,因此在可能出现数据竞争时使用同步方法和语句。在一个名为 testDispatchWorstCase 的单元测试中,将同时启动 100 到 500 个线程,每个线程都使用同步语句调用方法,这些语句利用单个控制器对象的监视器,称为 MasterSemaphore。使用 100 个线程进行测试时,有时一切正常,有时我在一个或多个同步语句和/或方法中遇到 stackoverflow 异常。在使用 500 个线程进行测试时,我几乎总是在一个或多个同步语句和/或方法中遇到 stackoverflow 异常。
MasterSemaphore 提供了用于锁定同步语句的监视器,还提供了一些事件处理方法,这些方法被调用来协调各个线程对资源的访问。鉴于此,我想也许可以使用 MasterSemaphore 的成员对象,它没有其他职责,因为监视器提供者会解决问题——不幸的是,这只会导致死锁;数百个线程在 Eclipse 的调试器线程视图中停留在“监视器”状态并永远保持这种状态。 我的问题如下:
对象的监视器如何存储和跟踪对受此监视器锁定的线程的引用?
为什么我在为监视器提供程序使用 MasterSemaphore 的成员对象时遇到了死锁?我需要在 synchronizes 语句中显式调用 wait...notifyAll 吗?
当数百个线程受制于一个对象的监视器锁时,什么可能导致同步语句中的堆栈溢出?
堆栈跟踪是:
01-02 07:47:44.910 27698 27842 E AndroidRuntime: FATAL EXCEPTION: HPCHead Spawned
Thread #24
01-02 07:47:44.910 27698 27842 E AndroidRuntime: java.lang.StackOverflowError
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:147)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
java.lang.IntegralToString.convertInt(IntegralToString.java:209)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
java.lang.IntegralToString.appendInt(IntegralToString.java:173)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
java.lang.StringBuilder.append(StringBuilder.java:139)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
java.lang.Thread.toString(Thread.java:1098)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
addRegistrantForCallback_PrefabEventHandling(MasterSemaphore.java:2524)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterEventHandler$EventIDFreedHandler.
onUpdateNeeded(MasterEventHandler.java:221)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.CallbackDataRecord.
postToQueueHead(CallbackDataRecord.java:107)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
onFinishedEventProcessing(MasterSemaphore.java:1219)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
addRegistrantForCallback_PrefabEventHandling(MasterSemaphore.java:2597)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterEventHandler$EventIDFreedHandler.
onUpdateNeeded(MasterEventHandler.java:221)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.CallbackDataRecord.
postToQueueHead(CallbackDataRecord.java:107)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
onFinishedEventProcessing(MasterSemaphore.java:1219)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
addRegistrantForCallback_PrefabEventHandling(MasterSemaphore.java:2597)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterEventHandler$EventIDFreedHandler
.onUpdateNeeded(MasterEventHandler.java:221)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.CallbackDataRecord.
postToQueueHead(CallbackDataRecord.java:107)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
onFinishedEventProcessing(MasterSemaphore.java:1219)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
addRegistrantForCallback_PrefabEventHandling(MasterSemaphore.java:2597)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterEventHandler$EventIDFreedHandler.
onUpdateNeeded(MasterEventHandler.java:221)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.CallbackDataRecord.
postToQueueHead(CallbackDataRecord.java:107)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
onFinishedEventProcessing(MasterSemaphore.java:1219)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
addRegistrantForCallback_PrefabEventHandling(MasterSemaphore.java:2597)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterEventHandler$EventIDFreedHandler.
onUpdateNeeded(MasterEventHandler.java:221)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.CallbackDataRecord.
postToQueueHead(CallbackDataRecord.java:107)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
onFinishedEventProcessing(MasterSemaphore.java:1219)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
addRegistrantForCallback_PrefabEventHandling(MasterSemaphore.java:2597)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterEventHandler$EventIDFreedHandler.
onUpdateNeeded(MasterEventHandler.java:221)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.CallbackDataRecord.
postToQueueHead(CallbackDataRecord.java:107)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
onFinishedEventProcessing(MasterSemaphore.java:1219)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
addRegistrantForCallback_PrefabEventHandling(MasterSemaphore.java:2597)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterEventHandler$EventIDFreedHandler.
onUpdateNeeded(MasterEventHandler.java:221)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.CallbackDataRecord.
postToQueueHead(CallbackDataRecord.java:107)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
onFinishedEventProcessing(MasterSemaphore.java:1219)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
addRegistrantForCallback_PrefabEventHandling(MasterSemaphore.java:2597)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterEventHandler$EventIDFreedHandler.
onUpdateNeeded(MasterEventHandler.java:221)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.CallbackDataRecord.
postToQueueHead(CallbackDataRecord.java:107)
01-02 07:47:44.910 27698 27842 E AndroidRuntime: at
com.hdradio.hdradiomanagerjc.hpc.MasterSemaphore.
onFinishedEventProcessing(MasterSemaphore.java:1219)
【问题讨论】:
-
你能发布 StackOverflowException 的堆栈跟踪吗?
-
StackOverflow 异常应该与同步问题无关。听起来完全不同的问题。同步只会导致线程阻塞和方法串行执行而不是并行执行。您根本不需要使用等待/通知。
-
我不希望堆栈溢出来自同步相关问题。这可能是一个不同的错误。我看到的唯一例外是您在 Android 上执行此操作。那里的 JavaVM 是否根据线程数调整堆栈大小? Java 通常为每个线程提供 512k 的堆栈(注意:很大程度上取决于许多因素),但也许 Android 具有适应性并给您提供很小、很小、很小的堆栈?
-
@DavidWasser 这是我的想法,我希望这可能是这种情况......我只是想我会把问题放在那里,以防我错过了关于 Java 内存模型的一些重要内容.我还编辑了问题以包含堆栈跟踪
-
堆栈跟踪在哪里?
标签: java android concurrency stack-overflow