From 684f28d8c40ae7187227e92f26630c146bb293b7 Mon Sep 17 00:00:00 2001 From: calvin1978 Date: Sat, 21 Jan 2017 10:42:38 +0800 Subject: [PATCH] =?UTF-8?q?#539=20JDK=E4=BE=9D=E8=B5=96=E6=94=B9=E4=B8=BAJ?= =?UTF-8?q?DK7.0+?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .travis.yml | 8 +- modules/utils/pom-release.xml | 4 +- modules/utils/pom.xml | 2 +- .../utils/base/SystemPropertiesUtil.java | 2 - .../modules/utils/collection/QueueUtil.java | 6 +- .../concurrent/jsr166e/RecursiveAction.java | 166 ++++++++++++++++++ .../concurrent/jsr166e/RecursiveTask.java | 71 ++++++++ .../springside/modules/utils/io/IOUtil.java | 28 --- .../modules/utils/number/RandomUtil.java | 10 +- 9 files changed, 250 insertions(+), 47 deletions(-) create mode 100644 modules/utils/src/main/java/org/springside/modules/utils/concurrent/jsr166e/RecursiveAction.java create mode 100644 modules/utils/src/main/java/org/springside/modules/utils/concurrent/jsr166e/RecursiveTask.java diff --git a/.travis.yml b/.travis.yml index 70645f06..de516eaf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,13 @@ jdk: install: true script: - - "cd modules;mvn clean test" - - jdk_switcher use oraclejdk8 - - "mvn test" + - "cd modules;mvn clean test" - jdk_switcher use oraclejdk8 - "mvn clean test" + - mvn clean package -Dmaven.test.skip=true + - jdk_switcher use oraclejdk7 + - "mvn test" + - "mvn clean package -Dmaven.test.skip=true" - jdk_switcher use oraclejdk7 - "mvn test" diff --git a/modules/utils/pom-release.xml b/modules/utils/pom-release.xml index 3b880e52..53c4a889 100644 --- a/modules/utils/pom-release.xml +++ b/modules/utils/pom-release.xml @@ -26,12 +26,12 @@ 1.7.22 1.1.8 4.12 - 2.2.0 + 2.6.0 1.10.19 UTF-8 - 1.6 + 1.7 ${java.version} ${java.version} diff --git a/modules/utils/pom.xml b/modules/utils/pom.xml index 5c87cab3..20d31572 100644 --- a/modules/utils/pom.xml +++ b/modules/utils/pom.xml @@ -23,7 +23,7 @@ UTF-8 - 1.6 + 1.7 ${java.version} ${java.version} diff --git a/modules/utils/src/main/java/org/springside/modules/utils/base/SystemPropertiesUtil.java b/modules/utils/src/main/java/org/springside/modules/utils/base/SystemPropertiesUtil.java index fb57d6d9..760c1aa5 100644 --- a/modules/utils/src/main/java/org/springside/modules/utils/base/SystemPropertiesUtil.java +++ b/modules/utils/src/main/java/org/springside/modules/utils/base/SystemPropertiesUtil.java @@ -4,7 +4,6 @@ import java.util.List; import java.util.Properties; import java.util.concurrent.CopyOnWriteArrayList; -import org.springside.modules.utils.base.SystemPropertiesUtil.PropertiesListener; import org.springside.modules.utils.number.NumberUtil; /** @@ -198,7 +197,6 @@ public class SystemPropertiesUtil { * Properties 本质上是一个HashTable,每次读写都会加锁,所以不支持频繁的System.getProperty(name)来检查系统内容变化 因此扩展了一个ListenableProperties, * 在其所关心的属性变化时进行通知. * - * @see PropertiesUtil#registerSystemPropertiesListener(PropertiesListener) * @see PropertiesListener */ public static class ListenableProperties extends Properties { diff --git a/modules/utils/src/main/java/org/springside/modules/utils/collection/QueueUtil.java b/modules/utils/src/main/java/org/springside/modules/utils/collection/QueueUtil.java index 946f4772..f64c51fc 100644 --- a/modules/utils/src/main/java/org/springside/modules/utils/collection/QueueUtil.java +++ b/modules/utils/src/main/java/org/springside/modules/utils/collection/QueueUtil.java @@ -45,10 +45,10 @@ public abstract class QueueUtil { } /** - * 创建无阻塞情况下,性能最优的并发双端队列 (兼容JDK6的情况) + * 创建无阻塞情况下,性能最优的并发双端队列 */ public static Deque newConcurrentNonBlockingDeque() { - return new java.util.concurrent.ConcurrentLinkedDeque(); + return new java.util.concurrent.ConcurrentLinkedDeque(); } /** @@ -106,8 +106,6 @@ public abstract class QueueUtil { /** * 支持后进先出的并发栈,用ConcurrentLinkedDeque实现,经过Collections#asLifoQueue()转换顺序 * - * 兼容了JDK6 - * * 另对于BlockingQueue接口, JDK暂无Lifo倒转实现,因此只能直接使用未调转顺序的LinkedBlockingDeque * * @see Collections#asLifoQueue() diff --git a/modules/utils/src/main/java/org/springside/modules/utils/concurrent/jsr166e/RecursiveAction.java b/modules/utils/src/main/java/org/springside/modules/utils/concurrent/jsr166e/RecursiveAction.java new file mode 100644 index 00000000..05b8c40f --- /dev/null +++ b/modules/utils/src/main/java/org/springside/modules/utils/concurrent/jsr166e/RecursiveAction.java @@ -0,0 +1,166 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package org.springside.modules.utils.concurrent.jsr166e; + +/** + * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/RecursiveAction.java 1.3 + * + * A recursive resultless {@link ForkJoinTask}. This class + * establishes conventions to parameterize resultless actions as + * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the + * only valid value of type {@code Void}, methods such as {@code join} + * always return {@code null} upon completion. + * + *

Sample Usages. Here is a simple but complete ForkJoin + * sort that sorts a given {@code long[]} array: + * + *

 {@code
+ * static class SortTask extends RecursiveAction {
+ *   final long[] array; final int lo, hi;
+ *   SortTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   SortTask(long[] array) { this(array, 0, array.length); }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD)
+ *       sortSequentially(lo, hi);
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new SortTask(array, lo, mid),
+ *                 new SortTask(array, mid, hi));
+ *       merge(lo, mid, hi);
+ *     }
+ *   }
+ *   // implementation details follow:
+ *   static final int THRESHOLD = 1000;
+ *   void sortSequentially(int lo, int hi) {
+ *     Arrays.sort(array, lo, hi);
+ *   }
+ *   void merge(int lo, int mid, int hi) {
+ *     long[] buf = Arrays.copyOfRange(array, lo, mid);
+ *     for (int i = 0, j = lo, k = mid; i < buf.length; j++)
+ *       array[j] = (k == hi || buf[i] < array[k]) ?
+ *         buf[i++] : array[k++];
+ *   }
+ * }}
+ * + * You could then sort {@code anArray} by creating {@code new + * SortTask(anArray)} and invoking it in a ForkJoinPool. As a more + * concrete simple example, the following task increments each element + * of an array: + *
 {@code
+ * class IncrementTask extends RecursiveAction {
+ *   final long[] array; final int lo, hi;
+ *   IncrementTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD) {
+ *       for (int i = lo; i < hi; ++i)
+ *         array[i]++;
+ *     }
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new IncrementTask(array, lo, mid),
+ *                 new IncrementTask(array, mid, hi));
+ *     }
+ *   }
+ * }}
+ * + *

The following example illustrates some refinements and idioms + * that may lead to better performance: RecursiveActions need not be + * fully recursive, so long as they maintain the basic + * divide-and-conquer approach. Here is a class that sums the squares + * of each element of a double array, by subdividing out only the + * right-hand-sides of repeated divisions by two, and keeping track of + * them with a chain of {@code next} references. It uses a dynamic + * threshold based on method {@code getSurplusQueuedTaskCount}, but + * counterbalances potential excess partitioning by directly + * performing leaf actions on unstolen tasks rather than further + * subdividing. + * + *

 {@code
+ * double sumOfSquares(ForkJoinPool pool, double[] array) {
+ *   int n = array.length;
+ *   Applyer a = new Applyer(array, 0, n, null);
+ *   pool.invoke(a);
+ *   return a.result;
+ * }
+ *
+ * class Applyer extends RecursiveAction {
+ *   final double[] array;
+ *   final int lo, hi;
+ *   double result;
+ *   Applyer next; // keeps track of right-hand-side tasks
+ *   Applyer(double[] array, int lo, int hi, Applyer next) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *
+ *   double atLeaf(int l, int h) {
+ *     double sum = 0;
+ *     for (int i = l; i < h; ++i) // perform leftmost base step
+ *       sum += array[i] * array[i];
+ *     return sum;
+ *   }
+ *
+ *   protected void compute() {
+ *     int l = lo;
+ *     int h = hi;
+ *     Applyer right = null;
+ *     while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) {
+ *       int mid = (l + h) >>> 1;
+ *       right = new Applyer(array, mid, h, right);
+ *       right.fork();
+ *       h = mid;
+ *     }
+ *     double sum = atLeaf(l, h);
+ *     while (right != null) {
+ *       if (right.tryUnfork()) // directly calculate if not stolen
+ *         sum += right.atLeaf(right.lo, right.hi);
+ *       else {
+ *         right.join();
+ *         sum += right.result;
+ *       }
+ *       right = right.next;
+ *     }
+ *     result = sum;
+ *   }
+ * }}
+ * + * @since 1.7 + * @author Doug Lea + */ +public abstract class RecursiveAction extends ForkJoinTask { + private static final long serialVersionUID = 5232453952276485070L; + + /** + * The main computation performed by this task. + */ + protected abstract void compute(); + + /** + * Always returns {@code null}. + * + * @return {@code null} always + */ + public final Void getRawResult() { return null; } + + /** + * Requires null completion value. + */ + protected final void setRawResult(Void mustBeNull) { } + + /** + * Implements execution conventions for RecursiveActions. + */ + protected final boolean exec() { + compute(); + return true; + } + +} diff --git a/modules/utils/src/main/java/org/springside/modules/utils/concurrent/jsr166e/RecursiveTask.java b/modules/utils/src/main/java/org/springside/modules/utils/concurrent/jsr166e/RecursiveTask.java new file mode 100644 index 00000000..4481585c --- /dev/null +++ b/modules/utils/src/main/java/org/springside/modules/utils/concurrent/jsr166e/RecursiveTask.java @@ -0,0 +1,71 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package org.springside.modules.utils.concurrent.jsr166e; + +/** + * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/RecursiveTask.java 1.4 + * + * A recursive result-bearing {@link ForkJoinTask}. + * + *

For a classic example, here is a task computing Fibonacci numbers: + * + *

 {@code
+ * class Fibonacci extends RecursiveTask {
+ *   final int n;
+ *   Fibonacci(int n) { this.n = n; }
+ *   protected Integer compute() {
+ *     if (n <= 1)
+ *       return n;
+ *     Fibonacci f1 = new Fibonacci(n - 1);
+ *     f1.fork();
+ *     Fibonacci f2 = new Fibonacci(n - 2);
+ *     return f2.compute() + f1.join();
+ *   }
+ * }}
+ * + * However, besides being a dumb way to compute Fibonacci functions + * (there is a simple fast linear algorithm that you'd use in + * practice), this is likely to perform poorly because the smallest + * subtasks are too small to be worthwhile splitting up. Instead, as + * is the case for nearly all fork/join applications, you'd pick some + * minimum granularity size (for example 10 here) for which you always + * sequentially solve rather than subdividing. + * + * @since 1.7 + * @author Doug Lea + */ +public abstract class RecursiveTask extends ForkJoinTask { + private static final long serialVersionUID = 5232453952276485270L; + + /** + * The result of the computation. + */ + V result; + + /** + * The main computation performed by this task. + * @return the result of the computation + */ + protected abstract V compute(); + + public final V getRawResult() { + return result; + } + + protected final void setRawResult(V value) { + result = value; + } + + /** + * Implements execution conventions for RecursiveTask. + */ + protected final boolean exec() { + result = compute(); + return true; + } + +} diff --git a/modules/utils/src/main/java/org/springside/modules/utils/io/IOUtil.java b/modules/utils/src/main/java/org/springside/modules/utils/io/IOUtil.java index 5e5e1593..bd4c51fa 100644 --- a/modules/utils/src/main/java/org/springside/modules/utils/io/IOUtil.java +++ b/modules/utils/src/main/java/org/springside/modules/utils/io/IOUtil.java @@ -8,10 +8,8 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; -import java.net.Socket; import java.util.ArrayList; import java.util.List; -import java.util.zip.ZipFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,32 +58,6 @@ public abstract class IOUtil { } } - /** - * For JDK6 which ZipFile is not Closeable. - */ - public static void closeQuietly(ZipFile zipfile) { - if (zipfile != null) { - try { - zipfile.close(); - } catch (IOException e) { - logger.warn(CLOSE_ERROR_MESSAGE, e); - } - } - } - - /** - * For JDK6 which Socket is not Closeable. - */ - public static void closeQuietly(Socket socket) { - if (socket != null) { - try { - socket.close(); - } catch (IOException e) { - logger.warn(CLOSE_ERROR_MESSAGE, e); - } - } - } - /** * 简单读取InputStream到String. */ diff --git a/modules/utils/src/main/java/org/springside/modules/utils/number/RandomUtil.java b/modules/utils/src/main/java/org/springside/modules/utils/number/RandomUtil.java index 4ca2a4f8..c561ff68 100644 --- a/modules/utils/src/main/java/org/springside/modules/utils/number/RandomUtil.java +++ b/modules/utils/src/main/java/org/springside/modules/utils/number/RandomUtil.java @@ -11,14 +11,12 @@ import org.springside.modules.utils.base.MoreValidate; /** * 随机数工具集. * - * 1. 获取无锁的兼容JDK6的ThreadLocalRandom + * 1. 获取无锁的ThreadLocalRandom, 性能较佳的SecureRandom * - * 2. 获取性能较佳的SecureRandom - * - * 3. 保证没有负数陷阱,也能更精确设定范围的nextInt/nextLong/nextDouble (copy from Common Lang + * 2. 保证没有负数陷阱,也能更精确设定范围的nextInt/nextLong/nextDouble (copy from Common Lang * RandomUtils,但默认使用性能较优的ThreadLocalRandom,并可配置其他的Random) * - * 4. 随机字符串 + * 3. 随机字符串 * * @author calvin */ @@ -27,8 +25,6 @@ public abstract class RandomUtil { /////////////////// 获取Random实例////////////// /** * 返回无锁的ThreadLocalRandom - * - * 如果JDK6,使用移植于jsr166e的版本(相当于JDK7的实现) */ public static Random threadLocalRandom() { return java.util.concurrent.ThreadLocalRandom.current();