我使用spring websocket和stomp开发了一个聊天系统。最近发现,有时许多线程(超过400个)在DefaultSubscriptionRegistry$DestinationCache$1
被阻止:
"http-nio-8686-exec-41" #3822 daemon prio=5 os_prio=0 tid=0x00007f26bc021000 nid=0x8c7a waiting for monitor entry [0x00007f2837af7000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry$DestinationCache.getSubscriptions(DefaultSubscriptionRegistry.java:269)
- waiting to lock <0x00000004c6969f98> (a org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry$DestinationCache$1)
at org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry.findSubscriptionsInternal(DefaultSubscriptionRegistry.java:184)
at org.springframework.messaging.simp.broker.AbstractSubscriptionRegistry.findSubscriptions(AbstractSubscriptionRegistry.java:116)
at org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.sendMessageToSubscribers(SimpleBrokerMessageHandler.java:328)
at org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.handleMessageInternal(SimpleBrokerMessageHandler.java:260)
at org.springframework.messaging.simp.broker.AbstractBrokerMessageHandler.handleMessage(AbstractBrokerMessageHandler.java:238)
at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135)
at org.springframework.messaging.support.ExecutorSubscribableChannel.sendInternal(ExecutorSubscribableChannel.java:91)
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:117)
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104)
at org.springframework.messaging.simp.SimpMessagingTemplate.sendInternal(SimpMessagingTemplate.java:184)
at org.springframework.messaging.simp.SimpMessagingTemplate.doSend(SimpMessagingTemplate.java:159)
at org.springframework.messaging.simp.SimpMessagingTemplate.doSend(SimpMessagingTemplate.java:47)
我认为使用
DestinationCache.getSubscriptions
在this.accessCache
中找不到目的地时,synchronized (this.updateCache)
将阻止。在某些情况下,此功能将导致许多线程被阻塞。
一种是模式目标,它不在accessCache中。
另一种情况是用户和目标太多,但默认情况下为
cacheLimit=1024
,因此某些内容将从高速缓存中删除。另一种情况是网络故障或其他原因,这导致许多WebSocket或所有WebSocket立即断开连接,但是消息通过使用
SimpMessagingTemplate.convertAndSend
来发送,然后,由于找不到目的地,线程将在DestinationCache.getSubscriptions
被阻止。我想知道是否有更好的避免阻塞的方法?
最佳答案
今天,我发现了同样的问题。看来增加cacheLimit
是个好方法。
一是模式目的地
用户可以按模式订阅目标,但是当您向目标发送消息时,目标的名称是已知的。
即getSubscriptions(...)
接受不是模式的destination
参数。
因此,再次增加cacheLimit
应该足以解决线程阻塞。
不幸的是,在春季WS XML配置中无法为cacheLimit
指定simple-broker
。可以向XML添加以下内容以绕过它:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler#0" />
<property name="targetMethod" value="setCacheLimit" />
<property name="arguments" value="8096"/>
</bean>