Optimization of System.currentTimeMillis() performance problem in high concurrency scenario

Keywords: Java SQL

Preface

The call of System.currentTimeMillis() takes more time than a normal object of new (I don't know how much more time it takes, but I heard it's about 100 times). However, this method is also a common method, sometimes it has to be used, such as generating wokerId, printing logs, etc. there must be performance problems in the high and emotional situation, but how to do it? The reason why System.currentTimeMillis() is slow is that it has dealt with the system once. So what's fast? Memory! If this method fetches data directly from memory, it will not be beautiful.

code implementation

package com.nyvi.support.util;

import java.sql.Timestamp;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * <p>
 * Optimization of System.currentTimeMillis() performance problem in high concurrency scenario
 * </p>
 * @author czk
 */
public class SystemClock {

    private final long period;

    private final AtomicLong now;

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

    private static SystemClock instance() {
        return InstanceHolder.INSTANCE;
    }

    public static long now() {
        return instance().currentTimeMillis();
    }

    public static String nowDate() {
        return new Timestamp(instance().currentTimeMillis()).toString();
    }

    private void scheduleClockUpdating() {

        ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {

            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r, "System Clock");
                thread.setDaemon(true);
                return thread;
            }
        });

        scheduler.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                now.set(System.currentTimeMillis());
            }
        }, period, period, TimeUnit.MILLISECONDS);
    }

    private long currentTimeMillis() {
        return now.get();
    }

    private static class InstanceHolder {
        public static final SystemClock INSTANCE = new SystemClock(1);
    }
}

When using, call SystemClock.now(); directly; it's ok.

test

Write a simple test code:

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (long i = 0; i < Integer.MAX_VALUE; i++) {
            SystemClock.now();
        }
        long end = System.currentTimeMillis();
        System.out.println("SystemClock Time:" + (end - start) + "Millisecond");
        long start2 = System.currentTimeMillis();
        for (long i = 0; i < Integer.MAX_VALUE; i++) {
            System.currentTimeMillis();
        }
        long end2 = System.currentTimeMillis();
        System.out.println("currentTimeMillis Time:" + (end2 - start2) + "Millisecond");
    }

The output is:
SystemClock Time:1787 MS
currentTimeMillis Time:33851 MS
Looking at the result, the efficiency improvement is quite obvious.

Posted by Mijii on Thu, 02 Apr 2020 03:22:29 -0700