From 60a147de5e3f56d810dacabf1e1773d8a12cd69d Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 26 Dec 2011 10:09:37 +0800 Subject: [PATCH] ha --- .../druid/pool/ha/MultiDataSource.java | 8 +- .../druid/pool/ha/balance/WeightBalancer.java | 7 +- .../alibaba/druid/util/ThreadLocalRandom.java | 193 ++++++++++++++++++ 3 files changed, 199 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/util/ThreadLocalRandom.java diff --git a/src/main/java/com/alibaba/druid/pool/ha/MultiDataSource.java b/src/main/java/com/alibaba/druid/pool/ha/MultiDataSource.java index a1337a6ad7..48365ad2b8 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/MultiDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/MultiDataSource.java @@ -7,7 +7,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executors; @@ -32,6 +31,7 @@ import com.alibaba.druid.pool.ha.valid.DataSourceFailureDetecter; import com.alibaba.druid.pool.ha.valid.DefaultDataSourceFailureDetecter; import com.alibaba.druid.proxy.jdbc.DataSourceProxy; import com.alibaba.druid.util.JdbcUtils; +import com.alibaba.druid.util.ThreadLocalRandom; public class MultiDataSource extends DataSourceAdapter implements MultiDataSourceMBean, DataSourceProxy { @@ -79,8 +79,6 @@ public class MultiDataSource extends DataSourceAdapter implements MultiDataSourc private ConfigLoader configLoader; - private Random random; - private int maxPoolSize = 50; private long activeCount = 0; @@ -178,8 +176,6 @@ public class MultiDataSource extends DataSourceAdapter implements MultiDataSourc return; } - random = new Random(); - initInternal(); scheduler = Executors.newScheduledThreadPool(schedulerThreadCount); @@ -377,7 +373,7 @@ public class MultiDataSource extends DataSourceAdapter implements MultiDataSourc return 0; } - return random.nextInt(totalWeight); + return ThreadLocalRandom.current().nextInt(totalWeight); } public MultiConnectionHolder getRealConnection(MultiDataSourceConnection multiConn, String sql) throws SQLException { diff --git a/src/main/java/com/alibaba/druid/pool/ha/balance/WeightBalancer.java b/src/main/java/com/alibaba/druid/pool/ha/balance/WeightBalancer.java index 7bf785280d..d0e02d194a 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/balance/WeightBalancer.java +++ b/src/main/java/com/alibaba/druid/pool/ha/balance/WeightBalancer.java @@ -15,9 +15,9 @@ public class WeightBalancer implements Balancer { public MultiConnectionHolder getConnection(MultiDataSourceConnection connectionProxy, String sql) throws SQLException { MultiDataSource multiDataSource = connectionProxy.getMultiDataSource(); - + long maxWaitMillis = multiDataSource.getMaxWaitMillis(); - + long startNano = -1; if (maxWaitMillis > 0) { startNano = System.nanoTime(); @@ -91,7 +91,8 @@ public class WeightBalancer implements Balancer { } if (dataSource == null) { - throw new SQLException("cannot get connection. enabledDataSourceCount " + multiDataSource.getEnabledDataSourceCount()); + throw new SQLException("cannot get connection. enabledDataSourceCount " + + multiDataSource.getEnabledDataSourceCount()); } return dataSource.getConnection(); diff --git a/src/main/java/com/alibaba/druid/util/ThreadLocalRandom.java b/src/main/java/com/alibaba/druid/util/ThreadLocalRandom.java new file mode 100644 index 0000000000..1a29716fbb --- /dev/null +++ b/src/main/java/com/alibaba/druid/util/ThreadLocalRandom.java @@ -0,0 +1,193 @@ +package com.alibaba.druid.util; + + + +import java.util.Random; + +/** + * A random number generator isolated to the current thread. Like the + * global {@link java.util.Random} generator used by the {@link + * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized + * with an internally generated seed that may not otherwise be + * modified. When applicable, use of {@code ThreadLocalRandom} rather + * than shared {@code Random} objects in concurrent programs will + * typically encounter much less overhead and contention. Use of + * {@code ThreadLocalRandom} is particularly appropriate when multiple + * tasks (for example, each a {@link ForkJoinTask}) use random numbers + * in parallel in thread pools. + * + *

Usages of this class should typically be of the form: + * {@code ThreadLocalRandom.current().nextX(...)} (where + * {@code X} is {@code Int}, {@code Long}, etc). + * When all usages are of this form, it is never possible to + * accidently share a {@code ThreadLocalRandom} across multiple threads. + * + *

This class also provides additional commonly used bounded random + * generation methods. + * + * @since 1.7 + * @author Doug Lea + */ +public class ThreadLocalRandom extends Random { + // same constants as Random, but must be redeclared because private + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; + + /** + * The random seed. We can't use super.seed. + */ + private long rnd; + + /** + * Initialization flag to permit calls to setSeed to succeed only + * while executing the Random constructor. We can't allow others + * since it would cause setting seed in one part of a program to + * unintentionally impact other usages by the thread. + */ + boolean initialized; + + // Padding to help avoid memory contention among seed updates in + // different TLRs in the common case that they are located near + // each other. + private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; + + /** + * The actual ThreadLocal + */ + private static final ThreadLocal localRandom = + new ThreadLocal() { + protected ThreadLocalRandom initialValue() { + return new ThreadLocalRandom(); + } + }; + + + /** + * Constructor called only by localRandom.initialValue. + */ + ThreadLocalRandom() { + super(); + initialized = true; + } + + /** + * Returns the current thread's {@code ThreadLocalRandom}. + * + * @return the current thread's {@code ThreadLocalRandom} + */ + public static ThreadLocalRandom current() { + return localRandom.get(); + } + + /** + * Throws {@code UnsupportedOperationException}. Setting seeds in + * this generator is not supported. + * + * @throws UnsupportedOperationException always + */ + public void setSeed(long seed) { + if (initialized) + throw new UnsupportedOperationException(); + rnd = (seed ^ multiplier) & mask; + } + + protected int next(int bits) { + rnd = (rnd * multiplier + addend) & mask; + return (int) (rnd >>> (48-bits)); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @throws IllegalArgumentException if least greater than or equal + * to bound + * @return the next value + */ + public int nextInt(int least, int bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextInt(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public long nextLong(long n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + // Divide n by two until small enough for nextInt. On each + // iteration (at most 31 of them but usually much less), + // randomly choose both whether to include high bit in result + // (offset) and whether to continue with the lower vs upper + // half (which makes a difference only if odd). + long offset = 0; + while (n >= Integer.MAX_VALUE) { + int bits = next(2); + long half = n >>> 1; + long nextn = ((bits & 2) == 0) ? half : n - half; + if ((bits & 1) == 0) + offset += n - nextn; + n = nextn; + } + return offset + nextInt((int) n); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public long nextLong(long least, long bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextLong(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed {@code double} value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public double nextDouble(double n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + return nextDouble() * n; + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public double nextDouble(double least, double bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextDouble() * (bound - least) + least; + } + + private static final long serialVersionUID = -5851777807851030925L; +}