Skip to content

Commit

Permalink
Use AtomicLongFieldUpdater in StepLong, StepDouble, and AtomicDouble
Browse files Browse the repository at this point in the history
Use AtomicLongFieldUpdater to shrink the footprint of StepLong, StepDouble, and AtomicDouble.
  • Loading branch information
kilink committed Sep 14, 2024
1 parent bf5a849 commit 645a878
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package com.netflix.spectator.impl;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;

/**
* Wrapper around AtomicLong to make working with double values easier.
Expand All @@ -26,22 +26,25 @@
@SuppressWarnings("PMD.MissingSerialVersionUID")
public class AtomicDouble extends Number {

private final AtomicLong value;
private volatile long value;

private static final AtomicLongFieldUpdater<AtomicDouble> VALUE_UPDATER = AtomicLongFieldUpdater.newUpdater(
AtomicDouble.class, "value");

/** Create an instance with an initial value of 0. */
public AtomicDouble() {
this(0.0);
super();
}

/** Create an instance with an initial value of {@code init}. */
public AtomicDouble(double init) {
super();
value = new AtomicLong(Double.doubleToLongBits(init));
this.value = Double.doubleToLongBits(init);
}

/** Return the current value. */
public double get() {
return Double.longBitsToDouble(value.get());
return Double.longBitsToDouble(value);
}

/** Add {@code amount} to the value and return the new value. */
Expand All @@ -51,11 +54,11 @@ public double addAndGet(double amount) {
double n;
long next;
do {
v = value.get();
v = value;
d = Double.longBitsToDouble(v);
n = d + amount;
next = Double.doubleToLongBits(n);
} while (!value.compareAndSet(v, next));
} while (!VALUE_UPDATER.compareAndSet(this, v, next));
return n;
}

Expand All @@ -66,17 +69,17 @@ public double getAndAdd(double amount) {
double n;
long next;
do {
v = value.get();
v = value;
d = Double.longBitsToDouble(v);
n = d + amount;
next = Double.doubleToLongBits(n);
} while (!value.compareAndSet(v, next));
} while (!VALUE_UPDATER.compareAndSet(this, v, next));
return d;
}

/** Set the value to {@code amount} and return the previous value. */
public double getAndSet(double amount) {
long v = value.getAndSet(Double.doubleToLongBits(amount));
long v = VALUE_UPDATER.getAndSet(this, Double.doubleToLongBits(amount));
return Double.longBitsToDouble(v);
}

Expand All @@ -87,15 +90,15 @@ public double getAndSet(double amount) {
public boolean compareAndSet(double expect, double update) {
long e = Double.doubleToLongBits(expect);
long u = Double.doubleToLongBits(update);
return value.compareAndSet(e, u);
return VALUE_UPDATER.compareAndSet(this, e, u);
}

/** Set the current value to {@code amount}. */
public void set(double amount) {
value.set(Double.doubleToLongBits(amount));
value = Double.doubleToLongBits(amount);
}

private boolean isGreaterThan(double v1, double v2) {
private static boolean isGreaterThan(double v1, double v2) {
return v1 > v2 || Double.isNaN(v2);
}

Expand Down Expand Up @@ -124,4 +127,9 @@ public void max(double v) {
@Override public double doubleValue() {
return get();
}

@Override
public String toString() {
return Double.toString(get());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import com.netflix.spectator.api.Clock;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;

/**
* Utility class for managing a set of AtomicLong instances mapped to a particular step interval.
Expand All @@ -37,7 +37,10 @@ public class StepDouble implements StepValue {
private volatile double previous;
private final AtomicDouble current;

private final AtomicLong lastInitPos;
private volatile long lastInitPos;

private static final AtomicLongFieldUpdater<StepDouble> LAST_INIT_POS_UPDATER = AtomicLongFieldUpdater.newUpdater(
StepDouble.class, "lastInitPos");

/** Create a new instance. */
public StepDouble(double init, Clock clock, long step) {
Expand All @@ -46,13 +49,13 @@ public StepDouble(double init, Clock clock, long step) {
this.step = step;
previous = init;
current = new AtomicDouble(init);
lastInitPos = new AtomicLong(clock.wallTime() / step);
lastInitPos = clock.wallTime() / step;
}

private void rollCount(long now) {
final long stepTime = now / step;
final long lastInit = lastInitPos.get();
if (lastInit < stepTime && lastInitPos.compareAndSet(lastInit, stepTime)) {
final long lastInit = lastInitPos;
if (lastInit < stepTime && LAST_INIT_POS_UPDATER.compareAndSet(this, lastInit, stepTime)) {
final double v = current.getAndSet(init);
// Need to check if there was any activity during the previous step interval. If there was
// then the init position will move forward by 1, otherwise it will be older. No activity
Expand Down Expand Up @@ -97,13 +100,13 @@ public double poll(long now) {

/** Get the timestamp for the end of the last completed interval. */
@Override public long timestamp() {
return lastInitPos.get() * step;
return lastInitPos * step;
}

@Override public String toString() {
return "StepDouble{init=" + init
+ ", previous=" + previous
+ ", current=" + current.get()
+ ", lastInitPos=" + lastInitPos.get() + '}';
+ ", lastInitPos=" + lastInitPos + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.netflix.spectator.api.Clock;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;

/**
* Utility class for managing a set of AtomicLong instances mapped to a particular step interval.
Expand All @@ -37,7 +38,10 @@ public class StepLong implements StepValue {
private volatile long previous;
private final AtomicLong current;

private final AtomicLong lastInitPos;
private volatile long lastInitPos;

private static final AtomicLongFieldUpdater<StepLong> LAST_INIT_POS_UPDATER = AtomicLongFieldUpdater.newUpdater(
StepLong.class, "lastInitPos");

/** Create a new instance. */
public StepLong(long init, Clock clock, long step) {
Expand All @@ -46,13 +50,13 @@ public StepLong(long init, Clock clock, long step) {
this.step = step;
previous = init;
current = new AtomicLong(init);
lastInitPos = new AtomicLong(clock.wallTime() / step);
lastInitPos = clock.wallTime() / step;
}

private void rollCount(long now) {
final long stepTime = now / step;
final long lastInit = lastInitPos.get();
if (lastInit < stepTime && lastInitPos.compareAndSet(lastInit, stepTime)) {
final long lastInit = lastInitPos;
if (lastInit < stepTime && LAST_INIT_POS_UPDATER.compareAndSet(this, lastInit, stepTime)) {
final long v = current.getAndSet(init);
// Need to check if there was any activity during the previous step interval. If there was
// then the init position will move forward by 1, otherwise it will be older. No activity
Expand Down Expand Up @@ -97,13 +101,13 @@ public long poll(long now) {

/** Get the timestamp for the end of the last completed interval. */
@Override public long timestamp() {
return lastInitPos.get() * step;
return lastInitPos * step;
}

@Override public String toString() {
return "StepLong{init=" + init
+ ", previous=" + previous
+ ", current=" + current.get()
+ ", lastInitPos=" + lastInitPos.get() + '}';
+ ", lastInitPos=" + lastInitPos + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,12 @@ public void maxValueInfinity() {
v.max(Double.POSITIVE_INFINITY);
Assertions.assertEquals(0.0, v.get(), 1e-12);
}

@Test
public void testToString() {
AtomicDouble v = new AtomicDouble(0.0);
Assertions.assertEquals("0.0", v.toString());
v.set(-100.5);
Assertions.assertEquals("-100.5", v.toString());
}
}

0 comments on commit 645a878

Please sign in to comment.