diff options
author | Håkon Hallingstad <hakon@oath.com> | 2018-12-20 14:08:42 +0100 |
---|---|---|
committer | Håkon Hallingstad <hakon@oath.com> | 2018-12-20 14:08:42 +0100 |
commit | 9922b4a419ecad5c9d4ea9e351f5e66e55fad84b (patch) | |
tree | 32abad6efa16653bacd5caaf559d456c3222a12e | |
parent | 58e87745267e02e051f6311024dc2fe980ec03a5 (diff) |
ThreadLocalRandom is recommended over Random in multithreaded environments, try 2
9 files changed, 48 insertions, 49 deletions
diff --git a/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java b/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java index d104b1a765b..a9bf1272133 100644 --- a/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java +++ b/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java @@ -10,7 +10,12 @@ import com.yahoo.jrt.Transport; import com.yahoo.system.CommandLineParser; import com.yahoo.vespa.config.ConfigDefinitionKey; import com.yahoo.vespa.config.ConfigKey; -import com.yahoo.vespa.config.protocol.*; +import com.yahoo.vespa.config.protocol.CompressionType; +import com.yahoo.vespa.config.protocol.DefContent; +import com.yahoo.vespa.config.protocol.JRTClientConfigRequest; +import com.yahoo.vespa.config.protocol.JRTClientConfigRequestV3; +import com.yahoo.vespa.config.protocol.JRTConfigRequestFactory; +import com.yahoo.vespa.config.protocol.Trace; import com.yahoo.vespa.config.util.ConfigUtils; import java.io.BufferedReader; @@ -25,7 +30,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; /** * A config client for generating load against a config server or config proxy. @@ -40,7 +45,6 @@ public class LoadTester { private Transport transport = new Transport(); protected Supervisor supervisor = new Supervisor(transport); private List<ConfigKey<?>> configs = new ArrayList<>(); - private Random random = new Random(System.currentTimeMillis()); private Map<ConfigDefinitionKey, Tuple2<String, String[]>> defs = new HashMap<>(); private long protocolVersion = Long.parseLong(JRTConfigRequestFactory.getProtocolVersion()); private CompressionType compressionType = JRTConfigRequestFactory.getCompressionType(); @@ -204,7 +208,7 @@ public class LoadTester { int totConfs = configs.size(); boolean reconnCycle = false; // to log reconn message only once, for instance at restart for (int i = 0; i < iterations; i++) { - reqKey = configs.get(random.nextInt(totConfs)); + reqKey = configs.get(ThreadLocalRandom.current().nextInt(totConfs)); ConfigDefinitionKey dKey = new ConfigDefinitionKey(reqKey); Tuple2<String, String[]> defContent = defs.get(dKey); if (defContent == null && defs.size() > 0) { // Only complain if we actually did run with a def dir diff --git a/jaxrs_client_utils/src/main/java/com/yahoo/vespa/jaxrs/client/JaxRsStrategyFactory.java b/jaxrs_client_utils/src/main/java/com/yahoo/vespa/jaxrs/client/JaxRsStrategyFactory.java index 1459024767d..9dbc472f4e2 100644 --- a/jaxrs_client_utils/src/main/java/com/yahoo/vespa/jaxrs/client/JaxRsStrategyFactory.java +++ b/jaxrs_client_utils/src/main/java/com/yahoo/vespa/jaxrs/client/JaxRsStrategyFactory.java @@ -7,8 +7,8 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Objects; -import java.util.Random; import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; /** * The idea behind this class is twofold: @@ -66,10 +66,8 @@ public class JaxRsStrategyFactory { return new NoRetryJaxRsStrategy<T>(hostName, port, jaxRsClientFactory, apiClass, pathPrefix, scheme); } - private static final Random random = new Random(); - private static <T> T getRandom(final Collection<? extends T> collection) { - int index = random.nextInt(collection.size()); + int index = ThreadLocalRandom.current().nextInt(collection.size()); return getIndex(collection, index); } diff --git a/jrt/src/com/yahoo/jrt/slobrok/api/SlobrokList.java b/jrt/src/com/yahoo/jrt/slobrok/api/SlobrokList.java index 9a89e3edc3f..b524c25d8ff 100644 --- a/jrt/src/com/yahoo/jrt/slobrok/api/SlobrokList.java +++ b/jrt/src/com/yahoo/jrt/slobrok/api/SlobrokList.java @@ -2,7 +2,7 @@ package com.yahoo.jrt.slobrok.api; import java.util.Arrays; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; public class SlobrokList { @@ -67,10 +67,9 @@ public class SlobrokList { for (int i = 0; i < slobroks.length; i++) { next[i] = slobroks[i]; } - Random rnd = new Random(); for (int i = 0; i + 1 < next.length; i++) { int lim = next.length - i; - int x = rnd.nextInt(lim); + int x = ThreadLocalRandom.current().nextInt(lim); if (x != 0) { String tmp = next[i]; next[i] = next[i+x]; diff --git a/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCService.java b/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCService.java index e3989a22c66..abe1b7b4db3 100644 --- a/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCService.java +++ b/messagebus/src/main/java/com/yahoo/messagebus/network/rpc/RPCService.java @@ -4,7 +4,7 @@ package com.yahoo.messagebus.network.rpc; import com.yahoo.jrt.slobrok.api.IMirror; import com.yahoo.jrt.slobrok.api.Mirror; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; /** * An RPCService represents a set of remote sessions matching a service pattern. The sessions are monitored using the @@ -16,7 +16,7 @@ public class RPCService { private final IMirror mirror; private final String pattern; - private int addressIdx = new Random().nextInt(Integer.MAX_VALUE); + private int addressIdx = ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE); private int addressGen = 0; private Mirror.Entry[] addressList = null; diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/executor/RunletExecutorImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/executor/RunletExecutorImpl.java index 1f647a7fb31..1e2547cc762 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/executor/RunletExecutorImpl.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/executor/RunletExecutorImpl.java @@ -4,10 +4,10 @@ package com.yahoo.vespa.service.executor; import com.yahoo.log.LogLevel; import java.time.Duration; -import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; @@ -18,9 +18,6 @@ import java.util.logging.Logger; public class RunletExecutorImpl implements RunletExecutor { private static Logger logger = Logger.getLogger(RunletExecutorImpl.class.getName()); - // About 'static': Javadoc says "Instances of java.util.Random are threadsafe." - private static final Random random = new Random(); - private final AtomicInteger executionId = new AtomicInteger(0); private final ConcurrentHashMap<Integer, CancellableImpl> cancellables = new ConcurrentHashMap<>(); private final ScheduledThreadPoolExecutor executor; @@ -30,7 +27,7 @@ public class RunletExecutorImpl implements RunletExecutor { } public Cancellable scheduleWithFixedDelay(Runlet runlet, Duration delay) { - Duration initialDelay = Duration.ofMillis((long) random.nextInt((int) delay.toMillis())); + Duration initialDelay = Duration.ofMillis((long) ThreadLocalRandom.current().nextInt((int) delay.toMillis())); CancellableImpl cancellable = new CancellableImpl(runlet); ScheduledFuture<?> future = executor.scheduleWithFixedDelay(cancellable, initialDelay.toMillis(), delay.toMillis(), TimeUnit.MILLISECONDS); cancellable.setPeriodicExecutionCancellationCallback(() -> future.cancel(false)); diff --git a/vespa-hadoop/src/main/java/com/yahoo/vespa/hadoop/mapreduce/VespaRecordWriter.java b/vespa-hadoop/src/main/java/com/yahoo/vespa/hadoop/mapreduce/VespaRecordWriter.java index 75607be3dfd..600658067cb 100644 --- a/vespa-hadoop/src/main/java/com/yahoo/vespa/hadoop/mapreduce/VespaRecordWriter.java +++ b/vespa-hadoop/src/main/java/com/yahoo/vespa/hadoop/mapreduce/VespaRecordWriter.java @@ -1,24 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hadoop.mapreduce; -import java.io.IOException; -import java.io.StringReader; -import java.util.List; -import java.util.Random; -import java.util.StringTokenizer; -import java.util.logging.Logger; - -import javax.xml.namespace.QName; -import javax.xml.stream.FactoryConfigurationError; -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; - -import org.apache.hadoop.mapreduce.RecordWriter; -import org.apache.hadoop.mapreduce.TaskAttemptContext; - import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParser; @@ -35,6 +17,22 @@ import com.yahoo.vespa.http.client.config.Endpoint; import com.yahoo.vespa.http.client.config.FeedParams; import com.yahoo.vespa.http.client.config.FeedParams.DataFormat; import com.yahoo.vespa.http.client.config.SessionParams; +import org.apache.hadoop.mapreduce.RecordWriter; +import org.apache.hadoop.mapreduce.TaskAttemptContext; + +import javax.xml.namespace.QName; +import javax.xml.stream.FactoryConfigurationError; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import java.io.IOException; +import java.io.StringReader; +import java.util.List; +import java.util.StringTokenizer; +import java.util.concurrent.ThreadLocalRandom; +import java.util.logging.Logger; /** * VespaRecordWriter sends the output <key, value> to one or more Vespa @@ -133,7 +131,7 @@ public class VespaRecordWriter extends RecordWriter { private void initialize() { if (!configuration.dryrun() && configuration.randomStartupSleepMs() > 0) { - int delay = new Random().nextInt(configuration.randomStartupSleepMs()); + int delay = ThreadLocalRandom.current().nextInt(configuration.randomStartupSleepMs()); log.info("VespaStorage: Delaying startup by " + delay + " ms"); try { Thread.sleep(delay); diff --git a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/core/communication/GatewayThrottler.java b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/core/communication/GatewayThrottler.java index cc637904553..189fd348c0e 100644 --- a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/core/communication/GatewayThrottler.java +++ b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/core/communication/GatewayThrottler.java @@ -1,7 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.http.client.core.communication; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; /** * When the gateways says it can not handle more load, we should send less load. That is the responsibility @@ -13,7 +13,6 @@ public class GatewayThrottler { private long backOffTimeMs = 0; private final long maxSleepTimeMs; - private static Random random = new Random(); public GatewayThrottler(long maxSleepTimeMs) { this.maxSleepTimeMs = maxSleepTimeMs; @@ -39,7 +38,7 @@ public class GatewayThrottler { } public int distribute(int expected) { - double factor = 0.5 + random.nextDouble(); + double factor = 0.5 + ThreadLocalRandom.current().nextDouble(); Double result = expected * factor; return result.intValue(); } diff --git a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/core/operationProcessor/IncompleteResultsThrottler.java b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/core/operationProcessor/IncompleteResultsThrottler.java index 6ecbb56888e..7cf4e32a880 100644 --- a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/core/operationProcessor/IncompleteResultsThrottler.java +++ b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/core/operationProcessor/IncompleteResultsThrottler.java @@ -3,7 +3,7 @@ package com.yahoo.vespa.http.client.core.operationProcessor; import com.yahoo.vespa.http.client.core.ThrottlePolicy; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; /** * Adjusts in-flight operations based on throughput. It will walk the graph and try to find @@ -34,11 +34,10 @@ public class IncompleteResultsThrottler { private final ConcurrentDocumentOperationBlocker blocker = new ConcurrentDocumentOperationBlocker(); private final int maxInFlightValue; private final int minInFlightValue; - private final Random random = new Random(); private final ThrottlePolicy policy; // 9-11 seconds with some randomness to avoid fully synchronous feeders. - public final long phaseSizeMs = 9000 + (random.nextInt() % 2000); + public final long phaseSizeMs = 9000 + (ThreadLocalRandom.current().nextInt() % 2000); private final Clock clock; private final Object monitor = new Object(); @@ -129,7 +128,7 @@ public class IncompleteResultsThrottler { private void adjustCycle() { adjustCycleCount++; - stabilizingPhasesLeft = adjustCycleCount < 5 ? 1 : 2 + random.nextInt() % 2; + stabilizingPhasesLeft = adjustCycleCount < 5 ? 1 : 2 + ThreadLocalRandom.current().nextInt() % 2; double maxPerformanceChange = getCeilingDifferencePerformance(adjustCycleCount); boolean messagesQueued = minPermitsAvailable < 2; diff --git a/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedHandler.java b/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedHandler.java index 58457a8aa20..5294545ad50 100644 --- a/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedHandler.java +++ b/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedHandler.java @@ -8,7 +8,6 @@ import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; import com.yahoo.container.jdisc.LoggingRequestHandler; import com.yahoo.container.jdisc.messagebus.SessionCache; -import com.yahoo.container.logging.AccessLog; import com.yahoo.document.DocumentTypeManager; import com.yahoo.document.config.DocumentmanagerConfig; import com.yahoo.documentapi.metrics.DocumentApiMetrics; @@ -19,22 +18,28 @@ import com.yahoo.messagebus.ReplyHandler; import com.yahoo.messagebus.SourceSessionParams; import com.yahoo.metrics.simple.MetricReceiver; import com.yahoo.net.HostName; -import com.yahoo.yolean.Exceptions; import com.yahoo.vespa.http.client.core.Headers; import com.yahoo.vespa.http.client.core.OperationStatus; +import com.yahoo.yolean.Exceptions; import javax.inject.Inject; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.concurrent.BlockingQueue; -import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.zip.GZIPInputStream; @@ -71,7 +76,7 @@ public class FeedHandler extends LoggingRequestHandler { docTypeManager = createDocumentManager(documentManagerConfig); clients = new HashMap<>(); this.sessionCache = sessionCache; - sessionId = new AtomicLong(new Random(System.currentTimeMillis()).nextLong()); + sessionId = new AtomicLong(ThreadLocalRandom.current().nextLong()); feedReplyHandler = new FeedReplyReader(parentCtx.getMetric(), metricsHelper); cron = new ScheduledThreadPoolExecutor(1, ThreadFactoryFactory.getThreadFactory("feedhandler.cron")); cron.scheduleWithFixedDelay(new CleanClients(), 16, 11, TimeUnit.MINUTES); |