自 Java 8 以来旧库并发编译失败

Compiling failure of old library concurrent since Java 8

数学库colt(1.2版)依赖库EDU.oswego.cs.dl.util.concurrent(gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html).编译 concurrent(版本 1.3.4)适用于 java 版本 7 或以前的版本。但是 编译在 java 8 上失败(javac 版本 1.8)。编译器选项 -source 1.4 -target 1.4 无法解决问题。

原因是,java8在接口java.util.Map中引入了一个新方法"remove":default boolean remove(Object key, Object value)。 这个新方法与实现 java.util.Map 的库 class ConcurrentHashMap.java 中的方法 "remove" 冲突: protected Object remove(Object key, Object value).

一旦确定了问题的原因,我就可以通过 重命名库 class ConcurrentHashMap.java 中的方法 来解决问题。这是可以接受的,因为库方法仅受到保护(而不是 public)。

是否有其他可能性来确保 java 8 兼容性?

没有编译器选项或注释会忽略冲突的方法签名。

如果你(或者,在这种情况下,colt)不使用新的remove方法,只需在Java 7下编译它。在 Java 8 下编译它不会给你任何优势。

但在这种情况下我更喜欢你的解决方案。

考虑到此 class 是 JRE class 也称为 ConcurrentHashMap 的基础,这里没有名称冲突,因为该方法具有完全预期的语义。发生冲突,因为方法是protected,一个早就修改过的决定。 IE。当您查看 class 的 Java 5 版本时,您会发现它已经具有 the method remove(Object, Object) and it’s public. It’s also demanded by the ConcurrentMap interface,因此 必须是 public.

所以最简单的修复方法不是重命名,而是将修饰符更改为 public 并适配 return 类型。


但你是对的, in the long term, the best solution is to migrate to the JRE version of that class as recommend by the author himself:

Note: Upon release of J2SE 5.0, this package enters maintenance mode: Only essential corrections will be released. J2SE5 package java.util.concurrent includes improved, more efficient, standardized versions of the main components in this package. Please plan to convert your applications to use them.

这是十多年前的事了……

将 colt 从 EDU.oswego.cs.dl.util.concurrent 迁移到 java.util.concurrent 类。正如 Holger 的回答中引用的那样,concurrent 库作者建议这样做。

Gentoo 为 colt 1.2.0 源代码提供了patch

--- src/cern/colt/matrix/linalg/SmpBlas.java.orig   2015-10-07 22:23:44.969486000 +0000
+++ src/cern/colt/matrix/linalg/SmpBlas.java    2015-10-07 22:29:15.475486000 +0000
@@ -10,7 +10,8 @@

 import cern.colt.matrix.DoubleMatrix1D;
 import cern.colt.matrix.DoubleMatrix2D;
-import EDU.oswego.cs.dl.util.concurrent.FJTask;
+
+import java.util.concurrent.ForkJoinTask;
 /**
 Parallel implementation of the Basic Linear Algebra System for symmetric multi processing boxes.
 Currently only a few algorithms are parallelised; the others are fully functional, but run in sequential mode.
@@ -198,7 +199,7 @@

    // set up concurrent tasks
    int span = width/noOfTasks;
-   final FJTask[] subTasks = new FJTask[noOfTasks];
+   final ForkJoinTask[] subTasks = new ForkJoinTask[noOfTasks];
    for (int i=0; i<noOfTasks; i++) {
        final int offset = i*span;
        if (i==noOfTasks-1) span = width - span*i; // last span may be a bit larger
@@ -217,24 +218,30 @@
            CC = C.viewPart(offset,0,span,p);
        }

-       subTasks[i] = new FJTask() { 
+       subTasks[i] = new ForkJoinTask() { 
            public void run() { 
                seqBlas.dgemm(transposeA,transposeB,alpha,AA,BB,beta,CC); 
                //System.out.println("Hello "+offset); 
            }
+
+      public boolean exec() { return true; }
+      public void setRawResult(Object o) {}
+      public Object getRawResult() {return null;}
        };
    }

    // run tasks and wait for completion
-   try { 
-       this.smp.taskGroup.invoke(
-           new FJTask() {
-               public void run() { 
-                   coInvoke(subTasks); 
-               }
-           }
-       );
-   } catch (InterruptedException exc) {}
+  this.smp.taskGroup.invoke(
+          new ForkJoinTask() {
+              public void run() {  
+                  invokeAll(subTasks); 
+              }
+
+              public boolean exec() { return true; }
+              public void setRawResult(Object o) {}
+              public Object getRawResult() {return null;}
+          }
+          );
 }
 public void dgemv(final boolean transposeA, final double alpha, DoubleMatrix2D A, final DoubleMatrix1D x, final double beta, DoubleMatrix1D y) {
    /*
@@ -271,7 +278,7 @@

    // set up concurrent tasks
    int span = width/noOfTasks;
-   final FJTask[] subTasks = new FJTask[noOfTasks];
+   final ForkJoinTask[] subTasks = new ForkJoinTask[noOfTasks];
    for (int i=0; i<noOfTasks; i++) {
        final int offset = i*span;
        if (i==noOfTasks-1) span = width - span*i; // last span may be a bit larger
@@ -280,24 +287,30 @@
        final DoubleMatrix2D AA = A.viewPart(offset,0,span,n);
        final DoubleMatrix1D yy = y.viewPart(offset,span);

-       subTasks[i] = new FJTask() { 
+       subTasks[i] = new ForkJoinTask() { 
            public void run() { 
                seqBlas.dgemv(transposeA,alpha,AA,x,beta,yy); 
                //System.out.println("Hello "+offset); 
            }
+
+      public boolean exec() { return true; }
+      public void setRawResult(Object o) {}
+      public Object getRawResult() {return null;}
        };
    }

    // run tasks and wait for completion
-   try { 
-       this.smp.taskGroup.invoke(
-           new FJTask() {
-               public void run() { 
-                   coInvoke(subTasks); 
-               }
-           }
-       );
-   } catch (InterruptedException exc) {}
+  this.smp.taskGroup.invoke(
+          new ForkJoinTask() {
+              public void run() {  
+                  invokeAll(subTasks); 
+              }
+
+              public boolean exec() { return true; }
+              public void setRawResult(Object o) {}
+              public Object getRawResult() {return null;}
+          }
+          );
 }
 public void dger(double alpha, DoubleMatrix1D x, DoubleMatrix1D y, DoubleMatrix2D A) {
    seqBlas.dger(alpha,x,y,A);
@@ -369,9 +382,6 @@
 /**
  * Prints various snapshot statistics to System.out; Simply delegates to {@link EDU.oswego.cs.dl.util.concurrent.FJTaskRunnerGroup#stats}.
  */
-public void stats() {
-   if (this.smp!=null) this.smp.stats();
-}
 private double xsum(DoubleMatrix2D A) {
    double[] sums = run(A,true,
        new Matrix2DMatrix2DFunction() {
--- src/cern/colt/matrix/linalg/Smp.java.orig   2015-10-07 21:08:19.443486000 +0000
+++ src/cern/colt/matrix/linalg/Smp.java    2015-10-07 22:28:24.722486000 +0000
@@ -9,12 +9,13 @@
 package cern.colt.matrix.linalg;

 import cern.colt.matrix.DoubleMatrix2D;
-import EDU.oswego.cs.dl.util.concurrent.FJTask;
-import EDU.oswego.cs.dl.util.concurrent.FJTaskRunnerGroup;
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.ForkJoinPool;
+
 /*
 */
 class Smp {
-   protected FJTaskRunnerGroup taskGroup; // a very efficient and light weight thread pool
+   protected ForkJoinPool taskGroup; // a very efficient and light weight thread pool

    protected int maxThreads;   
 /**
@@ -24,41 +25,39 @@
    maxThreads = Math.max(1,maxThreads);
    this.maxThreads = maxThreads;
    if (maxThreads>1) {
-       this.taskGroup = new FJTaskRunnerGroup(maxThreads);
+       this.taskGroup = new ForkJoinPool(maxThreads);
    }
    else { // avoid parallel overhead
        this.taskGroup = null;
    }
 }
-/**
- * Clean up deamon threads, if necessary.
- */
-public void finalize() {
-   if (this.taskGroup!=null) this.taskGroup.interruptAll();
-}
 protected void run(final DoubleMatrix2D[] blocksA, final DoubleMatrix2D[] blocksB, final double[] results, final Matrix2DMatrix2DFunction function) {
-   final FJTask[] subTasks = new FJTask[blocksA.length];
+   final ForkJoinTask[] subTasks = new ForkJoinTask[blocksA.length];
    for (int i=0; i<blocksA.length; i++) {
        final int k = i;
-       subTasks[i] = new FJTask() { 
+       subTasks[i] = new ForkJoinTask() { 
            public void run() {
                double result = function.apply(blocksA[k],blocksB != null ? blocksB[k] : null);
                if (results!=null) results[k] = result; 
                //System.out.print("."); 
            }
+      public boolean exec() { return true; }
+      public void setRawResult(Object o) {}
+      public Object getRawResult() {return null;}
        };
    }

    // run tasks and wait for completion
-   try { 
-       this.taskGroup.invoke(
-           new FJTask() {
-               public void run() { 
-                   coInvoke(subTasks); 
-               }
-           }
-       );
-   } catch (InterruptedException exc) {}
+  this.taskGroup.invoke(
+          new ForkJoinTask() {
+              public void run() {  
+                  invokeAll(subTasks); 
+              }
+              public boolean exec() { return true; }
+              public void setRawResult(Object o) {}
+              public Object getRawResult() {return null;}
+          }
+          );
 }
 protected DoubleMatrix2D[] splitBlockedNN(DoubleMatrix2D A, int threshold, long flops) {
    /*
@@ -186,10 +185,4 @@
    }
    return blocks;
 }
-/**
- * Prints various snapshot statistics to System.out; Simply delegates to {@link EDU.oswego.cs.dl.util.concurrent.FJTaskRunnerGroup#stats}.
- */
-public void stats() {
-   if (this.taskGroup!=null) this.taskGroup.stats();
-}
 }