TimeUnit類源碼詳解(concurrent包下的時間工具類)

目錄

 

1、TimeUnit介紹與基本使用

2、其它的操作方法

2.1、timedWait方法

2.2、timedJoin方法

2.3、sleep方法

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秒,代碼可讀性更好,還不用換算。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章