要使当前线程停放指定的超时,我可以使用:
LockSupport.parkNanos(long nanos);
或
Thread.sleep(long millis);//internally same as Object.wait(long) i guess.
不幸的是,这两种方法的内部滴答都是基于系统时钟的。
如果系统时钟在等待期间被更改(通过ntptime或手动),这些方法将不会被视为已被删除。
例如,在t0中,我调用此方法,如Thread.sleep(dt)来休眠dt秒。 在等待期间,我将系统时钟设置为提前20秒,然后线程将暂时休眠dt + 20秒。
使用以下代码进行检查:
public static void main(String[] args) throws InterruptedException {
long s = System.nanoTime();
int _10sec = 10 * 1000;
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(_10sec));
//or Thread.sleep(_10sec);
long e = System.nanoTime();
long used = e - s;
System.out.println("Used:" + TimeUnit.NANOSECONDS.toMillis(used)); }
使用诸如“date&& sudo date -s 16:10:40”之类的东西来设置你的系统时钟,等待几分钟,你会看到输出中发生了什么。
这很难过,因为在我的产品中,很多东西都是基于系统时钟的,
通过Socket连接为心跳检查器安排Scheduler(最后调用LockSupport.park)。如果系统时钟的前置时间超过超时时间,则调度程序会将其视为超时,但实际上并非超时。
任何人遇到同样的麻烦,你是如何解决的?
修改:
在我的HA产品中,我使用Watchdog在重负载阻塞系统时杀死操作系统(所谓的自杀策略)。我必须在内部喂狗以防止不必要的自杀,使用ThreadSupport.parkNanos(xxx)会有意想不到的自杀
答案 0 :(得分:1)
我要做的是定期进行睡眠唤醒,例如每秒,5秒或分钟。如果你想调整时间,它可以检查currentTimeMillis(),或者你想要单调增加时间nanoTime()。
答案 1 :(得分:0)
最后,我在Linux中使用JNI来解决这个问题。在Java范围内确实没有出路。
#include <jni.h>
#include <unistd.h>
#include <LinuxSleeper.h>
JNIEXPORT jint JNICALL Java_com_my_pkg_name_sleep_LinuxSleeper_sleep0
(JNIEnv *env, jobject thisObj, jint secs){
if( secs >= 0 ){
return sleep(secs);
}else{
return 0;
}
}
和java类看起来像:
public class LinuxSleeper extends CommonSleeper implements Sleeper {
static {
NativeUtils.loadLibrary("LinuxSleeper");
}
@Override
public int sleep(int seconds) {
///....
}
private native int sleep0(int seconds);
}