FULL PRODUCT VERSION :
java version "1.5.0_05"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode)
FULL OPERATING SYSTEM VERSION :
SunOS s0046mqa 5.7 Generic_106541-15 sun4us sparc FJSV,GPUS
A DESCRIPTION OF THE PROBLEM :
Summing up the elements of an int[] array using interfaces
for both the Iterator and the int wrapper Object takes 10
times(!) longer than using the concrete classes (on Solaris
7/SPARC, on Linux/Intel 2.3x, on WindowsNT 2.5x).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
for a in 0 1 2 3 4 5 6
do
java -server SlowInterface 1000000 20 20 $a
done
ACTUAL BEHAVIOR :
Linux on Pentium 4 mobile, 1.6 GHz, -server VM:
0: 215ms
1: 1715ms
2: 983ms
3: 1004ms
4: 264ms
5: 311ms
6: 160ms
Windows XP on Pentium 4, 2.4 GHz, 1Gb RAM, -server VM:
0: 94ms
1: 609ms
2: 594ms
3: 594ms
4: 188ms
5: 203ms
6: 78ms
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.*;
public class SlowInterface {
//----------------------------------------------------------------------
// int wrapper
//----------------------------------------------------------------------
private interface intReadRef {
int get ();
}
private interface intWriteRef {
void set (int value);
}
private interface intRef extends intReadRef, intWriteRef { }
private static final class MutableInt implements intRef {
private int value;
public MutableInt (int value) { this.value = value; }
public MutableInt () { }
public int get () { return value; }
public void set (int value) { this.value = value; }
}
//----------------------------------------------------------------------
// int[] iterators
//----------------------------------------------------------------------
private static abstract class IntArrayIterator implements Iterator {
protected final int[] a;
protected final int length;
protected int i;
protected int lastI = -1;
protected IntArrayIterator (int[] a, int i) { this.a = a; this.i = i;
length = a.length; }
public IntArrayIterator (int[] a) { this (a, 0); }
public final boolean hasNext () { return length > i; }
public final Object next () {
try {
return getUnchecked (lastI = i++);
} catch (ArrayIndexOutOfBoundsException e) {
throw new NoSuchElementException ("index: " + (lastI = --i)
+ ", length: " + length);
}
}
public final void remove () { throw new UnsupportedOperationException
(); }
protected abstract Object getUnchecked (int i);
}
private static final class MutableIterator extends IntArrayIterator {
private final MutableInt result = new MutableInt ();
public MutableIterator (int[] a) { super (a); }
protected Object getUnchecked (int i) { result.set (a [i]); return
result; }
}
//----------------------------------------------------------------------
private static final long run (int alg, int[] a, long expectedSum, int n) {
long start = System.currentTimeMillis ();
for (int r = 0; r < n; ++r) {
long s = 0;
switch (alg) {
case 0: {
for (int i = 0; i < a.length; ++i) {
s += a [i];
}
} break;
case 1: {
for (Iterator i = new MutableIterator (a); i.hasNext (); ) {
s += ((intReadRef)i.next ()).get ();
}
} break;
case 2: {
for (Iterator i = new MutableIterator (a); i.hasNext (); ) {
s += ((intRef)i.next ()).get ();
}
} break;
case 3: {
for (Iterator i = new MutableIterator (a); i.hasNext (); ) {
s += ((MutableInt)i.next ()).get ();
}
} break;
case 4: {
for (MutableIterator i = new MutableIterator (a); i.hasNext
(); ) {
s += ((intReadRef)i.next ()).get ();
}
} break;
case 5: {
for (MutableIterator i = new MutableIterator (a); i.hasNext
(); ) {
s += ((intRef)i.next ()).get ();
}
} break;
case 6: {
for (MutableIterator i = new MutableIterator (a); i.hasNext
(); ) {
s += ((MutableInt)i.next ()).get ();
}
} break;
}
if (s != expectedSum) {
throw new IllegalStateException ("wrong sum (expected: " +
expectedSum + "; actual: " + s + ")");
}
}
return System.currentTimeMillis () - start;
}
public static void main (String[] args) {
int length = Integer.parseInt (args [0]);
int warmup = Integer.parseInt (args [1]);
int measure = Integer.parseInt (args [2]);
int alg = Integer.parseInt (args [3]);
int[] a = new int [length];
long expectedSum = (length / 2L) * (length + 1L);
// fill
for (int i = 0; i < length; ++i) {
a [ i] = i + 1;
}
run (alg, a, expectedSum, warmup);
System.out.println (alg + ": " + run (alg, a, expectedSum, warmup)
+ "ms");
}
}
---------- END SOURCE ----------
CUSTOMER WORKAROUND :
Cast down to the concrete classes (not possible if concrete
classes are private inner classes).