|
|
@@ -11,6 +11,8 @@ import java.util.ArrayDeque;
|
|
|
import java.util.Deque;
|
|
|
import java.util.Map;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.function.Supplier;
|
|
|
+
|
|
|
import net.ranides.assira.collection.maps.IdentMap;
|
|
|
|
|
|
/**
|
|
|
@@ -31,12 +33,14 @@ public final class TimeMetric {
|
|
|
|
|
|
private final Deque<Long> stack = new ArrayDeque<>();
|
|
|
|
|
|
+ private final boolean threadsafe;
|
|
|
+
|
|
|
/**
|
|
|
* Creates new inactive stopwatch.
|
|
|
* Returned results are expressed in milliseconds by default.
|
|
|
*/
|
|
|
public TimeMetric() {
|
|
|
- this(TimeUnit.MILLISECONDS);
|
|
|
+ this(false);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -49,7 +53,29 @@ public final class TimeMetric {
|
|
|
* @param unit unit
|
|
|
*/
|
|
|
public TimeMetric(TimeUnit unit) {
|
|
|
+ this(false, unit);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates new inactive stopwatch.
|
|
|
+ * Returned results are expressed in milliseconds by default.
|
|
|
+ */
|
|
|
+ public TimeMetric(boolean threadsafe) {
|
|
|
+ this(threadsafe, TimeUnit.MILLISECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates new inactive stopwatch.
|
|
|
+ * Returned results are expressed in "unit" by default.
|
|
|
+ *
|
|
|
+ * Please note, that "unit" does not internal precision, but only default results returned
|
|
|
+ * by split or stop
|
|
|
+ *
|
|
|
+ * @param unit unit
|
|
|
+ */
|
|
|
+ public TimeMetric(boolean threadsafe, TimeUnit unit) {
|
|
|
this.unit = unit;
|
|
|
+ this.threadsafe = threadsafe;
|
|
|
start();
|
|
|
}
|
|
|
|
|
|
@@ -60,8 +86,10 @@ public final class TimeMetric {
|
|
|
* @return this
|
|
|
*/
|
|
|
public TimeMetric start() {
|
|
|
- stack.push(System.nanoTime());
|
|
|
- return this;
|
|
|
+ return $synchronized(() -> {
|
|
|
+ stack.push(System.nanoTime());
|
|
|
+ return this;
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -82,7 +110,9 @@ public final class TimeMetric {
|
|
|
* @return elapsed time
|
|
|
*/
|
|
|
public long stop(TimeUnit unit) {
|
|
|
- return time(unit, stack.pop());
|
|
|
+ return $synchronized(() -> {
|
|
|
+ return time(unit, stack.pop());
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -115,14 +145,27 @@ public final class TimeMetric {
|
|
|
* @return elapsed time
|
|
|
*/
|
|
|
public long time(TimeUnit unit) {
|
|
|
- if(stack.isEmpty()) {
|
|
|
- throw new IllegalStateException("#start must be called first");
|
|
|
+ return $synchronized(() -> {
|
|
|
+ if (stack.isEmpty()) {
|
|
|
+ throw new IllegalStateException("#start must be called first");
|
|
|
+ }
|
|
|
+ return time(unit, stack.peek());
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private <T> T $synchronized(Supplier<T> action) {
|
|
|
+ if(threadsafe) {
|
|
|
+ synchronized (stack) {
|
|
|
+ return action.get();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return action.get();
|
|
|
}
|
|
|
- return time(unit, stack.peek());
|
|
|
}
|
|
|
-
|
|
|
- private long time(TimeUnit unit, long dt) {
|
|
|
- return unit.convert(System.nanoTime() - dt, TimeUnit.NANOSECONDS);
|
|
|
+
|
|
|
+
|
|
|
+ private static long time(TimeUnit unit, long dt) {
|
|
|
+ return unit.convert(System.nanoTime() - dt, TimeUnit.NANOSECONDS);
|
|
|
}
|
|
|
|
|
|
@Override
|