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-2005 (C) Intalio Inc. All Rights Reserved.
42 *
43 * $Id: Clock.java,v 1.2 2005/03/25 13:22:01 tanderson Exp $
44 */
45 package org.exolab.jms.common.uuid;
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.2 $
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
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
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 (InterruptedException exception) {
217
218 synchronize();
219 } catch (ThreadDeath exception) {
220
221
222 _log.debug("clock daemon terminating", exception);
223 throw exception;
224 } catch (Throwable exception) {
225 _log.error("Internal error in clock daemon", exception);
226 }
227 }
228 }
229
230
231 public static synchronized long synchronize() {
232 long current;
233 long retarded;
234 long clock;
235 int adjust;
236
237 current = System.currentTimeMillis();
238 clock = _clock;
239 retarded = clock - _advance;
240
241 if (current != retarded) {
242 adjust = (int) (current - retarded) / _synchEvery;
243 if (adjust != 0) {
244 _adjust += adjust;
245
246
247
248
249
250 }
251 }
252
253 if (current > retarded) {
254 clock = current + _advance;
255 _clock = clock;
256 }
257 return clock;
258 }
259
260
261 private Clock() {
262 super("Clock Daemon");
263 _clock = System.currentTimeMillis();
264 setPriority(Thread.MAX_PRIORITY);
265 setDaemon(true);
266 start();
267 }
268
269 static {
270 new Clock();
271 }
272
273 public static void main(String[] args) {
274 long clock;
275 int count;
276
277 try {
278 count = 1000000;
279 System.out.println("Using Clock.clock()");
280 clock = System.currentTimeMillis();
281 for (int i = 0; i < count; ++i) {
282 if ((i % 100) == 0)
283 synchronize();
284 else
285 clock();
286 }
287 clock = System.currentTimeMillis() - clock;
288 System.out.println("Performed " + count + " in " + clock + "ms");
289 System.out.println("Using System.currentTimeMillis()");
290 clock = System.currentTimeMillis();
291 for (int i = 0; i < count; ++i)
292 System.currentTimeMillis();
293 clock = System.currentTimeMillis() - clock;
294 System.out.println("Performed " + count + " in " + clock + "ms");
295 } catch (Exception except) {
296 }
297 }
298
299 }