AppenderControlArraySet uses field updaters rather than AtomicReference
Very slightly reduces indirection to access the appender array.
Updates are relatively rare, so we don't need to worry about
noisy neighbors.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControlArraySet.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControlArraySet.java
index b0bcab8..54e89ab 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControlArraySet.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControlArraySet.java
@@ -20,7 +20,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.util.PerformanceSensitive;
@@ -32,7 +32,9 @@
*/
@PerformanceSensitive
public class AppenderControlArraySet {
- private final AtomicReference<AppenderControl[]> appenderArray = new AtomicReference<>(new AppenderControl[0]);
+ private static final AtomicReferenceFieldUpdater<AppenderControlArraySet, AppenderControl[]> appenderArrayUpdater =
+ AtomicReferenceFieldUpdater.newUpdater(AppenderControlArraySet.class, AppenderControl[].class, "appenderArray");
+ private volatile AppenderControl[] appenderArray = new AppenderControl[0];
/**
* Adds an AppenderControl to this set. If this set already contains the element, the call leaves the set unchanged
@@ -44,7 +46,7 @@
public boolean add(final AppenderControl control) {
boolean success;
do {
- final AppenderControl[] original = appenderArray.get();
+ final AppenderControl[] original = appenderArray;
for (final AppenderControl existing : original) {
if (existing.equals(control)) {
return false; // the appender is already in the list
@@ -52,7 +54,7 @@
}
final AppenderControl[] copy = Arrays.copyOf(original, original.length + 1);
copy[copy.length - 1] = control;
- success = appenderArray.compareAndSet(original, copy);
+ success = appenderArrayUpdater.compareAndSet(this, original, copy);
} while (!success); // could not swap: array was modified by another thread
return true; // successfully added
}
@@ -67,12 +69,12 @@
boolean success;
do {
success = true;
- final AppenderControl[] original = appenderArray.get();
+ final AppenderControl[] original = appenderArray;
for (int i = 0; i < original.length; i++) {
final AppenderControl appenderControl = original[i];
if (Objects.equals(name, appenderControl.getAppenderName())) {
final AppenderControl[] copy = removeElementAt(i, original);
- if (appenderArray.compareAndSet(original, copy)) {
+ if (appenderArrayUpdater.compareAndSet(this, original, copy)) {
return appenderControl; // successfully removed
}
success = false; // could not swap: array was modified by another thread
@@ -96,7 +98,7 @@
*/
public Map<String, Appender> asMap() {
final Map<String, Appender> result = new HashMap<>();
- for (final AppenderControl appenderControl : appenderArray.get()) {
+ for (final AppenderControl appenderControl : appenderArray) {
result.put(appenderControl.getAppenderName(), appenderControl.getAppender());
}
return result;
@@ -108,11 +110,11 @@
* @return the contents before this collection was cleared.
*/
public AppenderControl[] clear() {
- return appenderArray.getAndSet(new AppenderControl[0]);
+ return appenderArrayUpdater.getAndSet(this, new AppenderControl[0]);
}
public boolean isEmpty() {
- return appenderArray.get().length == 0;
+ return appenderArray.length == 0;
}
/**
@@ -121,11 +123,11 @@
* @return the array supporting this collection
*/
public AppenderControl[] get() {
- return appenderArray.get();
+ return appenderArray;
}
@Override
public String toString() {
- return "AppenderControlArraySet [appenderArray=" + appenderArray + "]";
+ return "AppenderControlArraySet [appenderArray=" + Arrays.toString(appenderArray) + "]";
}
}