Adam Maass said:
From personal experience in 1.0 and 1.1 JVMs (yes, it's been a long time),
"synchronized" had a 2-5x penalty.
It's probably better now, but I haven't bothered to check.
And this is where performance worries *really* need testing. Here we
have one vaguely remembered figure, and one which is irrelevant due to
the world having moved on.
Now, what operation are we interested in? Reading or writing? Let's
assume reading, for the moment. I've tested the following situations:
o Fetching elements from an ArrayList
o Fetching elements from a Vector
o Fetching elements from a String array (no casting)
o Fetching elements from an Object array and casting
For each iteration I took the length of the string element and added
that to a running total, so that the VM couldn't optimise away the
element access.
Here's the JBench (
http://www.pobox.com/~skeet/java/jbench) code for
the ArrayList test. The other classes are incredibly similar.
import uk.org.skeet.jbench.tasks.*;
import uk.org.skeet.jbench.*;
import java.util.*;
public class ArrayListTest extends SimpleTask
{
private ArrayList list;
private int iterations;
private long result;
public void setIterations (int iterations)
{
this.iterations = iterations;
}
public void prepareTest()
{
int size = (int) getSize();
list = new ArrayList (size);
for (int i=0; i < size; i++)
list.add ("hello");
}
public void runTest()
{
long totalLength=0;
int size = (int) getSize();
for (int i=0; i < iterations; i++)
{
for (int j=0; j < size; j++)
totalLength += ((String)list.get(j)).length();
}
result = totalLength;
}
public void checkResults() throws TaskException
{
if (result != 5*(int)getSize()*iterations)
throw new TaskException ("Invalid result");
}
}
Here's the properties file:
global.size = 10000
global.iterations = 10000
task.1.class = ArrayListTest
task.2.class = VectorTest
task.3.class = ArrayTestNoCast
task.4.class = ArrayTestWithCast
And here are the results:
--- JBench log starts Tue Jul 01 16:05:16 BST 2003 ---
General Configuration:
Number of test runs per task: 5
Abort on task configuration error: no
Excluding worst result and best result from stats.
System information:
VM: Java HotSpot(TM) Client VM;1.4.2-b28;Sun Microsystems Inc.
OS: Windows XP;x86;5.1
Timer: uk.org.skeet.jbench.ClockTimer; granularity: 10ms
Task configuration:
Configured 1: ArrayListTest; size=10,000
Configured 2: VectorTest; size=10,000
Configured 3: ArrayTestNoCast; size=10,000
Configured 4: ArrayTestWithCast; size=10,000
4 tasks successfully configured
----------
ArrayListTest; size=10,000
Testing.....All tests passed. Results:
8903ms
8913ms
8883ms
8993ms [excluded]
8863ms [excluded]
Mean=8899; variance=156; standard deviation=12
----------
VectorTest; size=10,000
Testing.....All tests passed. Results:
9313ms [excluded]
9144ms
9093ms
9153ms
9053ms [excluded]
Mean=9130; variance=698; standard deviation=26
----------
ArrayTestNoCast; size=10,000
Testing.....All tests passed. Results:
2664ms
2684ms
2654ms [excluded]
2674ms
2684ms [excluded]
Mean=2674; variance=66; standard deviation=8
----------
ArrayTestWithCast; size=10,000
Testing.....All tests passed. Results:
3816ms
3845ms
3826ms
3866ms [excluded]
3815ms [excluded]
Mean=3829; variance=144; standard deviation=12
--- JBench log ends Tue Jul 01 16:07:21 BST 2003 ---
So:
o Vector and ArrayList are roughly equal - synchronization is pretty
cheap now
o When the array is of the right type, accessing an element is at least
3-4x faster than using an ArrayList. (Don't forget we have the overhead
of calling String.length() 100 million times here.)
o When casting is required, the advantage falls quiet significantly -
nearly a third of the time spent by the ArrayTestWithCast test seemed
to be taken up casting.
Now, whether or not the difference between ArrayList and a plain array
is actually *significant* or not will depend on what you're planning to
do with the element - I chose the simplest thing I could think of in
order to minimise the impact on the results. (Taking the call out makes
a big difference; adding more calls doesn't change things much. Make of
that what you will...)
Personally I will almost always use a List when I've got something
which is probably going to be resized. The performance difference just
isn't worth the candle. Of course, I use an array for large sequences
of primitives - that's a different kettle of fish.
Anyway, still just microbenchmarking, but hopefully more useful than
the previous figures...