Appendix B. Performance tooling and empirical performance analysis 179
static int Num=1000;
public static void main(String[] args) {
o = new Object();
new ProfileTest().start(); /* start 3 threads */
new ProfileTest().start(); /* each thread executes the "run" method */
new ProfileTest().start();
}
public void run() {
double sum = 0.0;
for (int i = 0; i < 50000; i++) {
sum += doWork(); /* repeatedly do some work */
}
System.out.println("sum: "+sum); /* use the results of the work */
}
public double doWork() {
double d;
synchronized (o) { /* serialize the threads to create lock contention */
A = new Double [Num];
B = new Double [Num];
C = new Double [Num];
initialize();
calculate();
d = C[0].doubleValue();
}
return(d); /* use the calculated values */
}
public static void initialize() {
/* Initialize A and B. */
for (int i = 0; i < Num; i++) {
A[i] = new Double(Math.random()); /* use new to create objects */
B[i] = new Double(Math.random()); /* to force garbage collection */
}
}
public static void calculate() {
for (int i = 0; i < Num; i++) {
C[i] = new Double(A[i].doubleValue() * B[i].doubleValue());
}
}
}
The program also uses the Double class, creating many short-lived objects by using new. By
running the program with a small Java heap, GC frequently is required to free the Java heap
space that is taken by the Double objects that are no longer in use.