2013-05-06 78 views
1

我正在对Java中的事件回调处理框架进行压力测试,该框架在可能的情况下大量使用并发性,从而在数据竞争可能时使用同步方法和语句。在一个名为testDispatchWorstCase的恰当命名的单元测试中,任何地方都会有100到500个线程同时启动,每个线程都会调用具有同步语句的方法,这些语句利用称为MasterSemaphore的单个控制器对象的监视器。当使用100个线程进行测试时,有时一切都很完美,有时我会在一个或多个synchronized语句和/或方法中遇到一个stackoverflow异常。当使用500个线程进行测试时,我几乎总是在一个或多个同步语句和/或方法中遇到一个stackoverflow异常。Java并发性:导致StackOverflowError异常的同步语句/方法

MasterSemaphore提供了用于锁定同步语句的监视器,并提供了一些事件处理方法,这些方法被调用来协调各种线程对资源的访问。鉴于此,我认为可能使用MasterSemaphore的成员对象,因为监视器提供者可以解决问题 - 不过这只会导致死锁;数百个线程在eclipse的调试器线程视图中处于'monitor'状态,并且一直保持这种状态。 我的问题如下:

  1. 如何对象的监视器存储和跟踪对符合本显示器的锁线程参考?

  2. 为什么我会遇到使用MasterSemaphore成员对象的监视器提供程序的死锁?我是否需要在同步语句中显式调用wait ... notifyAll?

  3. 当数百个线程受到一个对象的监视器锁定时,什么可能导致同步语句中的堆栈溢出?

堆栈跟踪为:

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) 
+0

你能发布StackOverflowException的堆栈跟踪吗? – 2013-05-06 20:14:41

+4

StackOverflow异常与同步问题不应有任何关系。听起来像完全不同的问题。同步只会导致线程阻塞,并且会以串行方式执行而不是并行执行方法。你根本不需要等待/通知。 – 2013-05-06 20:23:08

+0

我不希望堆栈溢出来自同步相关的问题。这可能是一个不同的错误。我看到的唯一例外是你在Android上这样做。 JavaVM是否根据有多少线程来调整堆栈大小? Java通常为每个线程提供512k的堆栈(注意:严重依赖于许多因素),但是也许Android是适应性强的,并且可以为您提供细小的微小堆栈? – 2013-05-06 20:47:07

回答

1

问题的答案:

  1. 下面是一个article that describes how synchronization using object monitors works

  2. 我不知道为什么你结束了一个僵局。我需要看到更多的代码才能够提供帮助。正如我在我之前的评论中所说的那样,虽然你不需要使用wait'/ notifyAll when using synchronized . The JVM handles all the locking and waiting automatically for you. Of course, this doesn't mean that you can't program yourself into a deadlock situation (that's actually pretty easy to do). Adding notify()`虽然调用不会撤消死锁。

  3. 所以堆栈溢出问题是由递归调用堆栈看起来像这样的未来:

    ...

    MasterSemaphore.onFinishedEventProcessing(MasterSemaphore.java:1219) MasterSemaphore.addRegistrantForCallback_PrefabEventHandling(MasterSemaphore.java:2597) MasterEventHandler$EventIDFreedHandler.onUpdateNeeded(MasterEventHandler.java:221) CallbackDataRecord.postToQueueHead(CallbackDataRecord.java:107) MasterSemaphore.onFinishedEventProcessing(MasterSemaphore.java:1219)

所以onFinishedEventProcessing()被递归调用,这是导致堆栈溢出。你应该看看,看看为什么会发生(如果需要,添加一些日志记录)。