TimeUnit是一个枚举类型,共有NANOSECONDS,MICROSECONDS,MILLISECONDS,SECONDS,MINUTES,HOURS,DAYS 7个粒度,分别代表纳秒,微妙,毫秒,秒,分。小时。天。
所以也定义了7个转换方法。这里没有定义为抽象方法,是为了输出doc,因为定义为抽象方法就无法抽出doc了。抛出AbstractMethodError是为了让子类型全都重写这7个方法,否则使用未实现的抽象方法会抛AbstractMethodError。
public long toNanos(long duration) {
throw new AbstractMethodError();
}
public long toMicros(long duration) {
throw new AbstractMethodError();
}
public long toMillis(long duration) {
throw new AbstractMethodError();
}
public long toSeconds(long duration) {
throw new AbstractMethodError();
}
public long toMinutes(long duration) {
throw new AbstractMethodError();
}
public long toHours(long duration) {
throw new AbstractMethodError();
}
public long toDays(long duration) {
throw new AbstractMethodError();
}
除了7个转换方法,还有一个convert方法,实现的时候也是调用了上面的7个转换的方法之一。
public long convert(long sourceDuration, java.util.concurrent.TimeUnit sourceUnit) { throw new AbstractMethodError(); }
分析之前先将各个粒度的数值列出来,C0是一个单位的纳秒,C1是一个单位的微秒,是C0的1000倍......依次类推
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;
现在单独抽出一个HOURS来看看。
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, java.util.concurrent.TimeUnit u) { return u.toHours(d); } int excessNanos(long d, long m) { return 0; } }
可以看到,convert也是调用了toHours方法。toDays没有疑问,将输入的小时除以粒度的比值,得到粒度更大的天数,其实就是除以24。那么toNanos调用的x方法是干什么用的呢?我们看看它的定义:
/** * Scale d by m, checking for overflow. * This has a short name to make above code more readable. */ 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; }
套用HOURS,d就是输入的小时数,m是纳秒转换为小时的比值,即为C5/C0,over是转化为纳米所能允许的最大小时数,x方法为了防止overflow,进行了判断:
if (d > over) return Long.MAX_VALUE;
if (d < -over) return Long.MIN_VALUE;
d就是要换算的数值,m是换算比例,乘积是换算的结果,这时候跟小学时期换算单位是一样的。因为粒度大于等于毫秒的,总可以整个换算成毫秒,并没有遗留纳秒部分,所以全部返回0。
还有一个excessNanos方法是干什么用的呢?在HOURS里只是返回一个0。excessNanos注释可以看到,这是输入一个数值d和它的微秒部分m,然后抽出纳秒部分。
/** * Utility to compute the excess-nanosecond argument to wait, * sleep, join. * @param d the duration * @param m the number of milliseconds * @return the number of nanoseconds */ abstract int excessNanos(long d, long m);
拿MICROSECONDS来说,计算的过程是总值d乘以换算比例得到总纳秒值,然后减去微秒部分m换算成的纳秒值,就得到了纳秒部分。
int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
TimeUnit封装了Thread的join,sleep方法与Object的wait方法,有利于简化代码,提高可读性。excessNanos方法在这里提取了纳秒部分,派上了用场。
public void sleep(long timeout) throws InterruptedException { if (timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); Thread.sleep(ms, ns); } }