Java-時間單例線程

System.currentTimeMillis()在Java中是一個native方法,用于獲取當(dāng)前毫秒時間戳,雖然不用擔(dān)心線程安全問題,但是在超高并發(fā)的調(diào)用時會產(chǎn)生性能瓶頸。通常在記錄操作日志為了獲取時間都會去調(diào)用該方法,如果并發(fā)數(shù)量過大,會發(fā)現(xiàn)累積起來的性能損耗十分嚴(yán)重,為了減少調(diào)用該方法的次數(shù),可以使用時間單例解決。

目前網(wǎng)絡(luò)上流行的一種作法如下:

class SystemClock {
    private static final String THREAD_NAME = "system.clock";
    private static final SystemClock MILLIS_CLOCK = new SystemClock(1);
    private final long precision;
    private final AtomicLong now;

    private SystemClock(long precision) {
        this.precision = precision;
        now = new AtomicLong(System.currentTimeMillis());
        scheduleClockUpdating();
    }

    public static SystemClock millisClock() {
        return MILLIS_CLOCK;
    }

    private void scheduleClockUpdating() {
        ScheduledExecutorService scheduler =
                Executors.newSingleThreadScheduledExecutor(runnable -> {
                    Thread thread = new Thread(runnable, THREAD_NAME);
                    thread.setDaemon(true);
                    thread.setPriority(Thread.MAX_PRIORITY); //設(shè)置線程優(yōu)先級,讓時間線程盡可能運行(依賴于操作系統(tǒng)的調(diào)度實現(xiàn))
                    return thread;
                });
        scheduler.scheduleAtFixedRate(() ->
                now.set(System.currentTimeMillis()), precision, precision, TimeUnit.MILLISECONDS);
    }

    public long now() {
        return now.get();
    }
}

其實完全不需要依賴定時調(diào)度器ScheduledExecutorService 和線程安全的AtomicLong類,一個簡化的版本如下:

class SystemClock2 {
    private static final String THREAD_NAME = "system.clock2";
    private static final long TIME_TICK = 1;
    private static final SystemClock2 instance = new SystemClock2();
    private volatile long now = System.currentTimeMillis();

    public SystemClock2() {
        Thread timerThread = new Thread(() -> {
            while (true) {
                try {
                    TimeUnit.MILLISECONDS.sleep(TIME_TICK);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                now = System.currentTimeMillis();
            }
        }, THREAD_NAME);
        timerThread.setDaemon(true);
        timerThread.setPriority(Thread.MAX_PRIORITY); //設(shè)置線程優(yōu)先級,讓時間線程盡可能運行(依賴于操作系統(tǒng)的調(diào)度實現(xiàn))
        timerThread.start();
    }

    public static SystemClock2 getInstance() {
        return instance;
    }

    public long now() {
        return now;
    }
}

注:

  • 上述兩種實現(xiàn)方式都是按照1毫秒更新一次時間,也可自行按需設(shè)定。
  • 上述兩種單例模式都是“餓漢式”而不是“懶漢式”,因為該類被調(diào)用只可能用于獲取時間,因此第一次類初始化后就可以直接啟動時間更新線程了,同時可以減少“懶漢式”單例雙檢鎖(double-check lock)的判空步驟,性能更高。

性能測試程序如下:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class TimeSingleton {
    public static void main(String[] args) {
        int times = Integer.MAX_VALUE;

        new Thread(() -> {
            long start = System.currentTimeMillis();
            for (long j = 0; j < times; j++) {
                SystemClock.millisClock().now();
            }
            long end = System.currentTimeMillis();
            System.out.println("SystemClock Time:" + (end - start) + "毫秒");
        }).start();

        new Thread(() -> {
            long start = System.currentTimeMillis();
            for (long j = 0; j < times; j++) {
                SystemClock2.getInstance().now();
            }
            long end = System.currentTimeMillis();
            System.out.println("SystemClock2 Time:" + (end - start) + "毫秒");
        }).start();

        new Thread(() -> {
            long start = System.currentTimeMillis();
            for (long j = 0; j < times; j++) {
                System.currentTimeMillis();
            }
            long end = System.currentTimeMillis();
            System.out.println("SystemCurrentTimeMillis Time:" + (end - start) + "毫秒");
        }).start();

    }
}

在AMD 1700X,windows10 2004系統(tǒng)下測試結(jié)果:


對比實驗.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容