View Javadoc

1   /***
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio. Exolab is a registered
23   *    trademark of Intalio.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 1999-2004 (C) Intalio Inc. All Rights Reserved.
42   *
43   * $Id: Clock.java,v 1.4 2004/01/18 04:30:08 tanderson Exp $
44   */
45  package org.exolab.jms.util;
46  
47  import org.apache.commons.logging.Log;
48  import org.apache.commons.logging.LogFactory;
49  
50  
51  /***
52   * Provides an efficient mechanism for obtaining the current
53   * system time. Uses a background thread to automatically increment
54   * an internal clock and periodically synchronize with the system clock.
55   * The method {@link #clock clock} is more efficient than 
56   * <code>java.lang.System.currentTimeMillis</code>, and also
57   * allows the clock to be artificially advanced for testing purposes.
58   * <p>
59   * The clock is thread-safe and consumes a single thread.
60   * <p>
61   * This class originally came from Tyrex: http://tyrex.sourceforge.net
62   *
63   * @author <a href="mailto:arkin@intalio.com">Assaf Arkin</a>
64   * @version $Revision: 1.4 $
65   */
66  public final class Clock extends Thread {
67  
68      /***
69       * The number of clock ticks in each unsynchronized cycle.
70       * The default is 100 milliseconds.
71       */
72      public static final int UNSYNCH_TICKS = 100;
73  
74  
75      /***
76       * The number of unsychronized cycles before the clock is
77       * synchronized with the system clock. The default is 10.
78       */
79      public static final int SYNCH_EVERY = 10;
80  
81  
82      /***
83       * The current clock.
84       */
85      private static long _clock;
86  
87  
88      /***
89       * The number of clock ticks to skip before incrementing the internal
90       * clock.
91       */
92      private static int _unsynchTicks = UNSYNCH_TICKS;
93  
94      /***
95       * The number of cycles to skip before synchronizing with the system
96       * clock.
97       */
98      private static int _synchEvery = SYNCH_EVERY;
99  
100 
101     /***
102      * The amount of time in milliseconds by which to advance the clock
103      * compared to the system clock.
104      */
105     private static long _advance;
106 
107 
108     /***
109      * Used to adjust the clock when it gets out of synch. Based on the
110      * difference between the last clock and the system clock at the point of
111      * synchronization, divided by synchEvery.
112      */
113     private static int _adjust;
114 
115     /***
116      * The logger
117      */
118     private static final Log _log = LogFactory.getLog(Clock.class);
119 
120 
121     /***
122      * Returns the current clock.
123      *
124      * @return The current clock
125      */
126     public static synchronized long clock() {
127         // Synchronization is required since clock is a long.
128         return _clock;
129     }
130 
131 
132     /***
133      * Sets the number of clock ticks in each unsynchronized cycle.
134      * Use zero to restore the default value.
135      * <p>
136      * The internal clock is advanced every cycle, the length of the
137      * cycle is controlled by this property. A higher value results
138      * in a lower clock resolution.
139      *
140      * @param ticks The number of clock ticks (milliseconds) for
141      * each unsynchronized cycle
142      */
143     public static void setUnsynchTicks(int ticks) {
144         if (ticks <= 0) {
145             ticks = UNSYNCH_TICKS;
146         } else if (ticks < 100) {
147             ticks = 100;
148         }
149         _unsynchTicks = ticks;
150     }
151 
152 
153     /***
154      * Returns the number of clock ticks in each unsynchronized cycle.
155      *
156      * @return The number of clock ticks (milliseconds) for
157      * each unsynchronized cycle
158      */
159     public static int getUnsynchTicks() {
160         return _unsynchTicks;
161     }
162 
163 
164     /***
165      * Sets the number of unsynchronized cycles before the clock
166      * is synchronized with the system clock.
167      * <p>
168      * Synchronization will occur every <tt>unsynchTicks * synchEvery</tt>
169      * milliseconds. The larger the value, the less accurate
170      * the clock is.
171      *
172      * @param every The number of unsynchronized cycles
173      */
174     public static void setSynchEvery(int every) {
175         if (every <= 0)
176             every = SYNCH_EVERY;
177         _synchEvery = every;
178     }
179 
180 
181     /***
182      * Artficially advances the clock.
183      *
184      * @param byMillis The number of milliseconds by which to
185      * advance the clock (must be positive)
186      */
187     public synchronized static void advance(long byMillis) {
188         // Synchronization is required since clock is a long.
189         _advance += byMillis;
190         _clock += byMillis;
191     }
192 
193 
194     /***
195      * Returns the number of milliseconds by which the clock is
196      * advanced.
197      *
198      * @return The number of milliseconds by which the clock is
199      * advanced
200      */
201     public static long getAdvance() {
202         return _advance;
203     }
204 
205 
206     public void run() {
207         while (true) {
208             try {
209                 for (int i = 0; i < _synchEvery; ++i) {
210                     sleep(_unsynchTicks);
211                     synchronized (Clock.class) {
212                         _clock += _unsynchTicks + _adjust;
213                     }
214                 }
215                 synchronize();
216             } catch (Throwable exception) {
217                 _log.error("Internal error in clock daemon", exception);
218             }
219         }
220     }
221 
222 
223     public static synchronized long synchronize() {
224         long current;
225         long retarded;
226         long clock;
227         int adjust;
228 
229         current = System.currentTimeMillis();
230         clock = _clock;
231         retarded = clock - _advance;
232         // Adjust clock to new difference
233         if (current != retarded) {
234             adjust = (int) (current - retarded) / _synchEvery;
235             if (adjust != 0) {
236                 _adjust += adjust;
237                 /*
238                 if ( Configuration.verbose )
239                     Logger.tyrex.debug( "Clock late by " + ( current - retarded ) +
240                                         "ms -> synchronized, adjusting by " + _clock._adjust );
241                 */
242             }
243         }
244         // Make sure clock is progressive
245         if (current > retarded) {
246             clock = current + _advance;
247             _clock = clock;
248         }
249         return clock;
250     }
251 
252 
253     private Clock() {
254         super("Clock Daemon");
255         _clock = System.currentTimeMillis();
256         setPriority(Thread.MAX_PRIORITY);
257         setDaemon(true);
258         start();
259     }
260 
261     static {
262         new Clock();
263     }
264 
265     public static void main(String[] args) {
266         long clock;
267         int count;
268 
269         try {
270             count = 1000000;
271             System.out.println("Using Clock.clock()");
272             clock = System.currentTimeMillis();
273             for (int i = 0; i < count; ++i) {
274                 if ((i % 100) == 0)
275                     synchronize();
276                 else
277                     clock();
278             }
279             clock = System.currentTimeMillis() - clock;
280             System.out.println("Performed " + count + " in " + clock + "ms");
281             System.out.println("Using System.currentTimeMillis()");
282             clock = System.currentTimeMillis();
283             for (int i = 0; i < count; ++i)
284                 System.currentTimeMillis();
285             clock = System.currentTimeMillis() - clock;
286             System.out.println("Performed " + count + " in " + clock + "ms");
287         } catch (Exception except) {
288         }
289     }
290 
291 
292 }