I have pin pointed a bottle neck in my application, it seems to me that it boils down to a call to Thread::setContextClassLoader.
Basically I was forced to mess around with the thread's context class loader due to issues with 3rd party libraries (see this question to understand why).
The solution I picked was to my knowledge the common one and it works something like this:
Thread thread = Thread.currentThread();
ClassLoader old = thread.getContextClassLoader();
thread.setContextClassLoader(newClassLoader);
try {
... // problematic code that uses the thread context class loader
} finally {
thread.setContextClassLoader(old);
}
It turned out that the call to setContextClassLoader wasn't a problem when only 1 thread was running, but when more than one thread is doing it, it slows down drastically.
I've made the following test app to isolate the problem:
ArrayList<Thread> threads = new ArrayList<Thread>();
int thread_count = 1;
long start = System.currentTimeMillis();
for (int i = 0; i < thread_count; i++) {
Thread thread = new Thread(new MyRunnable(100000000));
thread.start();
threads.add(thread);
}
for (Thread thread : threads) {
thread.join();
}
long total = System.currentTimeMillis() - start;
double seconds = (double)total / 1000;
System.out.println("time in seconds: " + seconds);
And this is MyRunnable class:
public class MyRunnable implements Runnable {
int _iterations;
public MyRunnable(int iterations) {
_iterations = iterations;
}
public void run() {
final Thread curr = Thread.currentThread();
final ClassLoader loader = ClassLoader.getSystemClassLoader();
for (int i = 0; i < _iterations; i++) {
curr.setContextClassLoader(loader);
}
}
}
Basically it opens a couple of threads, and sets the current threads context class loader to the system class loader in a loop.
Updated results after code change on my machine: When thread_count
is 1 it finishes in half a second. 2 threads take 1.5~, 3 threads 2.7~, 4 threads 4~ - well you get the picture.
I've tried looking in Thread's implementation of setContextClassLoader and it appears that all it does is set a member variable to the class loader passed to it. I've found no locking (or access to shared resources that would require) to explain such overhead when running with more than one thread.
What am I missing here?
P.S. I'm using JRE 1.5 but the same thing happens in 1.6.
EDIT: @Tom Hawtin - See the code changes I made to rule out the reason you mentioned. Even when the system class loader is fetched once, the results are slower when the thread count > 1.