I am trying to find out about the performance difference between normal multithreading and multithreading using executor (to maintain a thread pool).
The below are code
Each thread consumes memory for stack, something from 256K to 1M. You can set stack size manually, but it is dangerous to set it below 128K. So If you have 2G memory and can afford to spend 1/2 for threads, you'll have no more than 8K threads. If this is ok for you, use normal multithreading (each Runnable has its own stack). If you are not willing or not able to spend so much memory for each Runnable, use Executor. Set thread pool size to the number of processors (Runtime.availableProcessors()), or several times more. The main problem arise, is that you cannot make Thread.sleep() or otherwise block thread in you runnable (say, wait for user response), because such blocking effectively excludes the thread from servicing. As a result, if you use thread pool of limited size, so called "thread starvation" occur, which is effectively a deadlock. If your thread pool is of unlimited size, then you fall back to normal multithreading and soon run out of memory.
The cure is to use asynchonous operations, that is, setup some request with your callback, and exit the run() method. The callback should then start execution of some Runnable object (maybe the same) with Executor.execute(Runnable), or it can execute the method runnable.run() itself.
Asynchronous input-output operations are present now in Java 7 (nio2), but I failed to make it serve more than several hundreds of network connections. For servicing network connections, asynchronous network libraries can be used (e.g. Apache Netty).
Organizing callbacks and execution of runnables may require sophisticated synchronization. To make life easier, consider to use Actor model (http://en.wikipedia.org/wiki/Actor_model), where Actor is a Runnable executing each time when an input message arrive. Numerous Java Actor libraries exist (e.g https://github.com/rfqu/df4j).