001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.util;
018    
019    import java.util.concurrent.locks.LockSupport;
020    
021    /**
022     * Implementation of the {@code Clock} interface that tracks the time in a
023     * private long field that is updated by a background thread once every
024     * millisecond. Timers on most platforms do not have millisecond granularity, so
025     * the returned value may "jump" every 10 or 16 milliseconds. To reduce this
026     * problem, this class also updates the internal time value every 1024 calls to
027     * {@code currentTimeMillis()}.
028     */
029    public final class CachedClock implements Clock {
030        private static final int UPDATE_THRESHOLD = 0x3FF;
031        private static final CachedClock instance = new CachedClock();
032        private volatile long millis = System.currentTimeMillis();
033        private volatile short count = 0;
034    
035        private CachedClock() {
036            final Thread updater = new Thread(new Runnable() {
037                @Override
038                public void run() {
039                    while (true) {
040                        final long time = System.currentTimeMillis();
041                        millis = time;
042    
043                        // avoid explicit dependency on sun.misc.Util
044                        LockSupport.parkNanos(1000 * 1000);
045                    }
046                }
047            }, "Clock Updater Thread");
048            updater.setDaemon(true);
049            updater.start();
050        }
051    
052        public static CachedClock instance() {
053            return instance;
054        }
055    
056        /**
057         * Returns the value of a private long field that is updated by a background
058         * thread once every millisecond. Timers on most platforms do not
059         * have millisecond granularity, the returned value may "jump" every 10 or
060         * 16 milliseconds. To reduce this problem, this method also updates the
061         * internal time value every 1024 calls.
062         * @return the cached time
063         */
064        @Override
065        public long currentTimeMillis() {
066    
067            // improve granularity: also update time field every 1024 calls.
068            // (the bit fiddling means we don't need to worry about overflows)
069            if ((++count & UPDATE_THRESHOLD) == UPDATE_THRESHOLD) {
070                millis = System.currentTimeMillis();
071            }
072            return millis;
073        }
074    }