Skip to content

Commit 776f0e5

Browse files
SergejIsbrechtSergej Isbrecht
and
Sergej Isbrecht
authored
2.x: Introduce property rx2.scheduler.use-nanotime (#7154) (#7170)
Co-authored-by: Sergej Isbrecht <[email protected]>
1 parent f31aed3 commit 776f0e5

File tree

3 files changed

+99
-6
lines changed

3 files changed

+99
-6
lines changed

src/main/java/io/reactivex/Scheduler.java

+36-6
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@
6161
* interface which can grant access to the original or hooked {@code Runnable}, thus, a repeated {@code RxJavaPlugins.onSchedule}
6262
* can detect the earlier hook and not apply a new one over again.
6363
* <p>
64-
* The default implementation of {@link #now(TimeUnit)} and {@link Worker#now(TimeUnit)} methods to return current
65-
* {@link System#currentTimeMillis()} value in the desired time unit. Custom {@code Scheduler} implementations can override this
64+
* The default implementation of {@link #now(TimeUnit)} and {@link Worker#now(TimeUnit)} methods to return current {@link System#currentTimeMillis()}
65+
* value in the desired time unit, unless {@code rx2.scheduler.use-nanotime} (boolean) is set. When the property is set to
66+
* {@code true}, the method uses {@link System#nanoTime()} as its basis instead. Custom {@code Scheduler} implementations can override this
6667
* to provide specialized time accounting (such as virtual time to be advanced programmatically).
6768
* Note that operators requiring a {@code Scheduler} may rely on either of the {@code now()} calls provided by
6869
* {@code Scheduler} or {@code Worker} respectively, therefore, it is recommended they represent a logically
@@ -89,6 +90,34 @@
8990
* All methods on the {@code Scheduler} and {@code Worker} classes should be thread safe.
9091
*/
9192
public abstract class Scheduler {
93+
/**
94+
* Value representing whether to use {@link System#nanoTime()}, or default as clock for {@link #now(TimeUnit)}
95+
* and {@link Scheduler.Worker#now(TimeUnit)}
96+
* <p>
97+
* Associated system parameter:
98+
* <ul>
99+
* <li>{@code rx2.scheduler.use-nanotime}, boolean, default {@code false}
100+
* </ul>
101+
*/
102+
static boolean IS_DRIFT_USE_NANOTIME = Boolean.getBoolean("rx2.scheduler.use-nanotime");
103+
104+
/**
105+
* Returns the current clock time depending on state of {@link Scheduler#IS_DRIFT_USE_NANOTIME} in given {@code unit}
106+
* <p>
107+
* By default {@link System#currentTimeMillis()} will be used as the clock. When the property is set
108+
* {@link System#nanoTime()} will be used.
109+
* <p>
110+
* @param unit the time unit
111+
* @return the 'current time' in given unit
112+
* @throws NullPointerException if {@code unit} is {@code null}
113+
*/
114+
static long computeNow(TimeUnit unit) {
115+
if(!IS_DRIFT_USE_NANOTIME) {
116+
return unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
117+
}
118+
return unit.convert(System.nanoTime(), TimeUnit.NANOSECONDS);
119+
}
120+
92121
/**
93122
* The tolerance for a clock drift in nanoseconds where the periodic scheduler will rebase.
94123
* <p>
@@ -131,7 +160,7 @@ public static long clockDriftTolerance() {
131160
* @since 2.0
132161
*/
133162
public long now(@NonNull TimeUnit unit) {
134-
return unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
163+
return computeNow(unit);
135164
}
136165

137166
/**
@@ -332,8 +361,9 @@ public <S extends Scheduler & Disposable> S when(@NonNull Function<Flowable<Flow
332361
* track the individual {@code Runnable} tasks while they are waiting to be executed (with or without delay) so that
333362
* {@link #dispose()} can prevent their execution or potentially interrupt them if they are currently running.
334363
* <p>
335-
* The default implementation of the {@link #now(TimeUnit)} method returns current
336-
* {@link System#currentTimeMillis()} value in the desired time unit. Custom {@code Worker} implementations can override this
364+
* The default implementation of the {@link #now(TimeUnit)} method returns current {@link System#currentTimeMillis()}
365+
* value in the desired time unit, unless {@code rx2.scheduler.use-nanotime} (boolean) is set. When the property is set to
366+
* {@code true}, the method uses {@link System#nanoTime()} as its basis instead. Custom {@code Worker} implementations can override this
337367
* to provide specialized time accounting (such as virtual time to be advanced programmatically).
338368
* Note that operators requiring a scheduler may rely on either of the {@code now()} calls provided by
339369
* {@code Scheduler} or {@code Worker} respectively, therefore, it is recommended they represent a logically
@@ -448,7 +478,7 @@ public Disposable schedulePeriodically(@NonNull Runnable run, final long initial
448478
* @since 2.0
449479
*/
450480
public long now(@NonNull TimeUnit unit) {
451-
return unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
481+
return computeNow(unit);
452482
}
453483

454484
/**

src/main/java/io/reactivex/schedulers/Schedulers.java

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
* <li>{@code rx2.single-priority} (int): sets the thread priority of the {@link #single()} Scheduler, default is {@link Thread#NORM_PRIORITY}</li>
4040
* <li>{@code rx2.purge-enabled} (boolean): enables periodic purging of all Scheduler's backing thread pools, default is false</li>
4141
* <li>{@code rx2.purge-period-seconds} (int): specifies the periodic purge interval of all Scheduler's backing thread pools, default is 1 second</li>
42+
* <li>{@code rx2.scheduler.use-nanotime} (boolean): {@code true} instructs {@code Scheduler} to use {@link System#nanoTime()} for {@link Scheduler#now(TimeUnit)},
43+
* instead of default {@link System#currentTimeMillis()} ({@code false})</li>
4244
* </ul>
4345
*/
4446
public final class Schedulers {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Copyright (c) 2016-present, RxJava Contributors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
5+
* compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is
10+
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
11+
* the License for the specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package io.reactivex;
15+
16+
import org.junit.After;
17+
import org.junit.Test;
18+
19+
import java.util.concurrent.TimeUnit;
20+
21+
import static org.junit.Assert.*;
22+
23+
/**
24+
* Same as {@link io.reactivex.schedulers.SchedulerTest}, but different package, to access
25+
* package-private fields.
26+
*/
27+
public class SchedulerTest {
28+
private static final String DRIFT_USE_NANOTIME = "rx2.scheduler.use-nanotime";
29+
30+
@After
31+
public void cleanup() {
32+
// reset value to default in order to not influence other tests
33+
Scheduler.IS_DRIFT_USE_NANOTIME = false;
34+
}
35+
36+
@Test
37+
public void driftUseNanoTimeNotSetByDefault() {
38+
assertFalse(Scheduler.IS_DRIFT_USE_NANOTIME);
39+
assertFalse(Boolean.getBoolean(DRIFT_USE_NANOTIME));
40+
}
41+
42+
@Test
43+
public void computeNow_currentTimeMillis() {
44+
TimeUnit unit = TimeUnit.MILLISECONDS;
45+
assertTrue(isInRange(System.currentTimeMillis(), Scheduler.computeNow(unit), unit, 250, TimeUnit.MILLISECONDS));
46+
}
47+
48+
@Test
49+
public void computeNow_nanoTime() {
50+
TimeUnit unit = TimeUnit.NANOSECONDS;
51+
Scheduler.IS_DRIFT_USE_NANOTIME = true;
52+
53+
assertFalse(isInRange(System.currentTimeMillis(), Scheduler.computeNow(unit), unit, 250, TimeUnit.MILLISECONDS));
54+
assertTrue(isInRange(System.nanoTime(), Scheduler.computeNow(unit), TimeUnit.NANOSECONDS, 250, TimeUnit.MILLISECONDS));
55+
}
56+
57+
private boolean isInRange(long start, long stop, TimeUnit source, long maxDiff, TimeUnit diffUnit) {
58+
long diff = Math.abs(stop - start);
59+
return diffUnit.convert(diff, source) <= maxDiff;
60+
}
61+
}

0 commit comments

Comments
 (0)