我们有一个用Java编写的RMI客户端应用程序,它需要定期向服务器应用程序发送“保持活动”消息。我们已经将它实现为一个单独的心跳线程,它将保持活动消息发送到服务器,然后使用Thread.sleep()休眠15秒。
线程设置为高优先级:
Thread heartbeatThread = new Thread(new HeartbeatRunnable(server));
heartbeatThread.setPriority(Thread.MAX_PRIORITY);
heartbeatThread.start();
但是,当运行客户端的框使用大量CPU时,我们发现错过了心跳,这导致服务器认为我们的客户端应用程序已经死亡。
我们在主线程中添加了Thread.yield()调用,虽然这没有解决问题。
有没有办法保证在我的应用程序仍在运行时按时发送心跳?
答案 0 :(得分:3)
你无法真正保证。您可以在不同的线程中发送心跳,以防止将心跳发送到延迟所需的时间。建议将两次心跳之间的延迟设置为服务器用于判断客户端死机的时间的一半,即如果服务器在15秒后超时运行,(尝试)每7.5秒发送一次心跳。 / p>
答案 1 :(得分:2)
这取决于使用CPU的过程。
如果这不是你的过程,所以客户端进程真的没有响应,那么所有意图和目的都没有活着,所以不发送心跳是合适的。有一个心跳消息说“我已经启动并可以处理消息”,当盒子太大而无法做到这一点时会产生误导。
如果心跳消息的意图是说'这个过程正在运行,但可能需要半个小时才能回到你身边',那么无论做什么处理都要将该消息发送给服务器。或者将超时设置为适合客户端响应的超时。
答案 2 :(得分:1)
您应该在决定客户端不可用之前配置服务器等待的“错过的心跳”的数量。
因此,例如,如果心跳间隔为15秒且错过的心跳数为4,则服务器将等待最多60秒(1分钟),然后才能确定客户端无法访问。
答案 3 :(得分:1)
您可以在代码中自由散布自编“yield”函数,在非线程环境中实现用户模式线程。
同样,您可以在代码中自由分散心跳检查函数调用。放弃线程,只需定期调用心跳功能,检查是否需要发送心跳。
这是一个粗略的解决方案,但鉴于你已经尝试了正确的解决方案并且它不起作用,也许这是你必须回归的东西。
实际上你可以做的是在每个函数调用的开头放置一个宏,它会快速检查时间并在必要时调用心跳功能。
(啊,你有Java的宏吗?我想不是 - 但你明白了。)
答案 4 :(得分:0)
也许最好的解决方案是使用Timer的scheduleAtFixedRate。有了这个,如果一个执行延迟(在Java中无法避免),后续调用将不会受到影响。
答案 5 :(得分:0)
如果您希望服务器宣布它处于活动状态,那么最好不要提供一个打开的套接字。在您的客户端上只需从该套接字读取。它会阻塞(因为你的服务器没有写任何东西),如果服务器消失/关闭你的客户端会得到一个IOException,表明服务器套接字/端口已经消失。
这不依赖于提供及时心跳的服务器。它使用的资源很少(服务器端的TCP端口,没有带宽),及时显示服务器(或服务器机器)不可用时。