我想在java中实现一个非常简单的客户端服务器心跳。最简单的方法似乎是通过睡眠。考虑下面的元代码。
class MyClass
Thread heartbeatThread = new Thread();
public void() startHeartBeat{
Thread.sleep(4000);
sock.write("H");
}
这是一个适当的解决方案,还是我不考虑陷阱?
我也考虑使用java.util.Timer.scheduleAtFixedRate
方法。这会更强大/可靠吗?如果是这样,为什么?这是一个例子(它不是干净的IMO):
class HeartBeat
{
Timer timer=new Timer();
public void scheduleHeartBeat(int delay, int period) {
timer.scheduleAtFixedRate( new HeartBeatTask(), delay, period);
}
}
class HeartBeatTaskextends TimerTask {
public void run() {
sock.write("H");
}
第二种方法会获得更高的优先级吗?
答案 0 :(得分:12)
首先,基于Thread
的习语不会在没有无限循环的情况下以固定费率安排。
这也是一个缺点:你可能想设置一些退出循环的条件。
在调用静态InterruptedException
时,您还需要捕获Thread.sleep
。
计划执行的另一个流行习语是使用ScheduledExecutorService
。
找到以下3个替代方案:
<强>定时器强>
// says "foo" every half second
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("foo");
}
}, 0, 500);
在固定速率执行中,每次执行都是相对于初始执行的预定执行时间进行调度的。如果由于任何原因(例如垃圾收集或其他后台活动)延迟执行,则会快速连续执行两次或更多次执行以“赶上”。
文档here。
无限循环
new Thread() {
@Override
public void run() {
while (true) {
// Says "blah" every half second
System.out.println("blah");
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
// nope
}
}
}
}.start();
Thread.sleep
仍然是受制于系统定时器和调度程序的精确性和准确性。 ......并且需要捕捉
InterruptedException
。
文档here。
此外:
try
/ catch
。<强>执行人强>
ScheduledExecutorService es = Executors.newSingleThreadScheduledExecutor();
es.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
// Says "bar" every half second
System.out.println("bar");
}
},
0, 500, TimeUnit.MILLISECONDS);
Callable
s(虽然不是固定费率)并重新使用{ {1}}。 ExecutorService
的文档实际上提及java.util.Timer
(实施ScheduledThreadPoolExecutor
界面)作为“ScheduledExecutorService
/ Timer
组合的更多功能替代品”。如果执行此任务的时间超过其期限,则后续执行可能会延迟,
文档here。
答案 1 :(得分:1)
如果您使用睡眠方法,则需要考虑一些问题。
一个是睡眠时间不准确,你可能会随着时间的推移而漂移(也许当你的线程正在睡觉时,另一个应用程序占用CPU并且你的线程需要比预期更长的时间来发送它的心跳,现在下一次线程发送心跳延迟),你的睡眠时间将逐渐增加各种事物(你不会睡眠时间少于你的睡眠时间,但可能经常睡觉多一点),这些增量会随着时间的推移而增加。
另一个问题是你可能遇到套接字问题,你必须编写代码来处理新的连接。
线程需要表现良好并响应中断,否则就是守护程序线程。如果必须跨线程共享数据,则需要了解内存可见性问题。
使用计时器意味着每次启动任务都会有一个新的开始,你不会容易受到累积的延迟或过时的网络连接的影响。
答案 2 :(得分:1)
是的,我不知道计时器是如何在内部实现的,但我在这里理解的是,如果你使用sleep,你将不得不处理InterruptedException,并且吃掉这个异常可能不是一个好习惯。此外,计时器任务将在其线程空间内运行,您可以更好地控制它。
如果需要,您可以随时停止计时器,在这种情况下,您可能无法执行此操作