目录
2.4、int excessNanos(long d, long m) 方法
1、TimeUnit介绍与基本使用
TimeUnit类的作用:用于时间的换算,比如纳秒,微秒,毫秒,秒,分钟,小时,天等等的换算。
下面看看TimeUnit的源码,提供了每个时间单位的换算方法。
public enum TimeUnit {
// 纳秒转换工具
NANOSECONDS {
public long toNanos(long d) { return d; }
public long toMicros(long d) { return d/(C1/C0); }
public long toMillis(long d) { return d/(C2/C0); }
public long toSeconds(long d) { return d/(C3/C0); }
public long toMinutes(long d) { return d/(C4/C0); }
public long toHours(long d) { return d/(C5/C0); }
public long toDays(long d) { return d/(C6/C0); }
public long convert(long d, TimeUnit u) { return u.toNanos(d); }
int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
},
// 微秒转换工具
MICROSECONDS {
public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); }
public long toMicros(long d) { return d; }
public long toMillis(long d) { return d/(C2/C1); }
public long toSeconds(long d) { return d/(C3/C1); }
public long toMinutes(long d) { return d/(C4/C1); }
public long toHours(long d) { return d/(C5/C1); }
public long toDays(long d) { return d/(C6/C1); }
public long convert(long d, TimeUnit u) { return u.toMicros(d); }
int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
},
// 毫秒转换工具
MILLISECONDS {
public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); }
public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); }
public long toMillis(long d) { return d; }
public long toSeconds(long d) { return d/(C3/C2); }
public long toMinutes(long d) { return d/(C4/C2); }
public long toHours(long d) { return d/(C5/C2); }
public long toDays(long d) { return d/(C6/C2); }
public long convert(long d, TimeUnit u) { return u.toMillis(d); }
int excessNanos(long d, long m) { return 0; }
},
// 秒转换工具
SECONDS {
public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); }
public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); }
public long toMillis(long d) { return x(d, C3/C2, MAX/(C3/C2)); }
public long toSeconds(long d) { return d; }
public long toMinutes(long d) { return d/(C4/C3); }
public long toHours(long d) { return d/(C5/C3); }
public long toDays(long d) { return d/(C6/C3); }
public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
int excessNanos(long d, long m) { return 0; }
},
// 分钟转换工具
MINUTES {
public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); }
public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); }
public long toMillis(long d) { return x(d, C4/C2, MAX/(C4/C2)); }
public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); }
public long toMinutes(long d) { return d; }
public long toHours(long d) { return d/(C5/C4); }
public long toDays(long d) { return d/(C6/C4); }
public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
int excessNanos(long d, long m) { return 0; }
},
// 小时转换工具
HOURS {
public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); }
public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); }
public long toMillis(long d) { return x(d, C5/C2, MAX/(C5/C2)); }
public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); }
public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); }
public long toHours(long d) { return d; }
public long toDays(long d) { return d/(C6/C5); }
public long convert(long d, TimeUnit u) { return u.toHours(d); }
int excessNanos(long d, long m) { return 0; }
},
// 天转换工具
DAYS {
public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); }
public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); }
public long toMillis(long d) { return x(d, C6/C2, MAX/(C6/C2)); }
public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); }
public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); }
public long toHours(long d) { return x(d, C6/C5, MAX/(C6/C5)); }
public long toDays(long d) { return d; }
public long convert(long d, TimeUnit u) { return u.toDays(d); }
int excessNanos(long d, long m) { return 0; }
};
// 这几个常量是时间转换的单位大小
static final long C0 = 1L;
static final long C1 = C0 * 1000L;
static final long C2 = C1 * 1000L;
static final long C3 = C2 * 1000L;
static final long C4 = C3 * 60L;
static final long C5 = C4 * 60L;
static final long C6 = C5 * 24L;
static final long MAX = Long.MAX_VALUE;
// 这个方法具体是什么意思,我不管了,反正是个TimeUnit类的内部使用而已
static long x(long d, long m, long over) {
if (d > over) return Long.MAX_VALUE;
if (d < -over) return Long.MIN_VALUE;
return d * m;
}
// 此处没有给出其它成员方法,不急,稍后介绍
}
具体怎么用呢?我们举个例子(2天换算成小时,再把48小时换算成天):
// 把2天换算成小时,有两种写法
long hours = TimeUnit.DAYS.toHours(2);
long hours2 = TimeUnit.HOURS.convert(2, TimeUnit.DAYS);
// 把48小时换算成天,有两种写法
long days = TimeUnit.HOURS.toDays(48);
long days2 = TimeUnit.DAYS.convert(48, TimeUnit.HOURS);
2、其它的操作方法
2.1、timedWait方法
作用:调用obj的wait()方法,让当前线程阻塞,阻塞的最长时间为timeout,超过了这个时间,该线程自动被唤醒。
第一个问题,timeout没有指定时间单位,我们怎么知道它代表多长时间呢?
是这样的,比如,TimeUnit.SECONDS.timedWait(obj,2.23441)代表2.23441秒,
TimeUnit.MILLISECONDS.timedWait(obj,2.23441)代表2.23441毫秒;
第二个问题,wait(ms, ns);ms是毫秒数,ns是纳秒数,为什么要这么写呢?
因为大部分CPU是做不到纳秒级的,都是毫秒就OK,但是我们有时没有办法让时间精度只精确到毫秒,比如就输入一个2.5657346464757575毫秒,你咋办,所以就保证毫秒的精度,对于后面更加细致的时间,直接四舍五入。
public void timedWait(Object obj, long timeout)
throws InterruptedException {
if (timeout > 0) {
long ms = toMillis(timeout);
int ns = excessNanos(timeout, ms);
obj.wait(ms, ns);
}
}
2.2、timedJoin方法
作用:让thread调用join()方法,放弃当前CPU的使用权(意味着等待),要放弃timeout这么久,等过了这个时间,thread再去竞争CPU的使用权接着运行。timeout的时间单位同上。
和直接调用某个线程的join(long ms, long ns) 方法没什么区别。
public void timedJoin(Thread thread, long timeout)
throws InterruptedException {
if (timeout > 0) {
long ms = toMillis(timeout);
int ns = excessNanos(timeout, ms);
thread.join(ms, ns);
}
}
2.3、sleep方法
作用:让当前线程睡眠timeout这么长的时间。timeout的单位同上。
public void sleep(long timeout) throws InterruptedException {
if (timeout > 0) {
long ms = toMillis(timeout);
int ns = excessNanos(timeout, ms);
Thread.sleep(ms, ns);
}
}
2.4、int excessNanos(long d, long m) 方法
excessNanos(long d, long m) 是供上面3个方法使用的,参数d是表示一段时间,具体是什么时间,要看调用上面3个方法的时间单位是哪个,比如 TimeUnit.HOURS.sleep(1.5).中1.5就表示1.5个小时,因此excessNanos(long d, long m)方法中的d此时也就表示小时。 参数m表示毫秒数。
上面这段可能讲得不好,举个例子就明白了,比如 time = 2.123456789秒,此时time里的毫秒就应该是m = 2.123,然后调用excessNanos(time, m) = ns,这里的ns = 456789 纳秒,意思就是将时间d分为 毫秒 + 纳秒,m为毫秒,返回的值为纳秒。
总结:上面3个方法都是对线程方面的wait、join、sleep方法进行了一层封装,可读性更好,因为用原始方法的话,需要我们自己去换算时间,比如sleep(2300),睡眠2.3秒,这都是比较简单的了(如果更加复杂了),要先将2.3秒换算成毫秒,其次读代码的时候,还要再次换算成秒,我们才能直接观地知道睡眠多久,可读性不好。但是如果使用TimeUnit工具类的话,可读性更好,不用我们去换算时间了,比如TimeUnit.SCONDS.sleep(2.3);睡眠2.3秒,代码可读性更好,还不用换算。