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
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 (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
233 if (current != retarded) {
234 adjust = (int) (current - retarded) / _synchEvery;
235 if (adjust != 0) {
236 _adjust += adjust;
237
238
239
240
241
242 }
243 }
244
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 }