Compiling failure of old library concurrent since Java 8

771 Views Asked by At

The math library colt (version 1.2) depends on the library EDU.oswego.cs.dl.util.concurrent (gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html). Compiling concurrent (version 1.3.4) worked on java version 7 or previous releases. However compiling fails on java 8 (javac version 1.8). Compiler options -source 1.4 -target 1.4 do not resolve the issue.

The reason is, that java 8 introduced a new method "remove" in the interface java.util.Map: default boolean remove(Object key, Object value). This new method clashes with the method "remove" in the library class ConcurrentHashMap.java which implements java.util.Map: protected Object remove(Object key, Object value).

Once the cause of the problem was identified I could resolve the issue by renaming the method in the library class ConcurrentHashMap.java. This was acceptable because the library method was protected only (and not public).

Are there other possibilities to ensure java 8 compatibility?

  • compiler options?
  • annotations ("@ForceOverride") ?
3

There are 3 best solutions below

2
On BEST ANSWER

There are no compiler options nor annotations that will ignore conflicting method signatures.

If you (or, in this case, colt) don't use the new remove method, just compile it under Java 7. Compiling it under Java 8 won't give you any advantage.

But I actually like your solution better in this case.

2
On

Considering that this class is the groundwork of the JRE class also known as ConcurrentHashMap, there is no name clash here, as that method has exactly the intended semantic. A clash occurs, because the method is protected, a decision which has already revised long ago. I.e. when you look at the Java 5 version of the class, you’ll see that it already has the method remove(Object, Object) and it’s public. It’s also demanded by the ConcurrentMap interface and thus must be public.

So the simplest fix is not to rename it, but to change the modifier to public and adapt the return type.


But you are right in your comment, 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.

And this was more than a decade ago…

1
On

Migrate colt from EDU.oswego.cs.dl.util.concurrent to java.util.concurrent classes. As cited in Holger's answer, the concurrent library author recommends doing so.

Gentoo provides a patch for the colt 1.2.0 source code:

--- 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();
-}
 }