The questions you DID ask:
- Yes, one thread means one CPU thread. Additional threads can use additional CPUs, as long as they have work to do. If you create more threads than CPUs, they will fight for CPU time and the result is often slower. Some CPUs use hyperthreading and expose more threads than actual cores (sometimes this gives a performance benefit). Use
Runtime.getRuntime.availableProcessors()
to show the suggested thread count.
- Yes, threads are not cheap to create and destroy, and there is a large overhead for each thread. Pooling and reusing threads is an extremely common pattern for this reason. Don't make a thread for every method call.
- The garbage collector already does its work in separate threads, but it will have to cause a "stop the world" pause for at least part of the GC in order to mark dead objects for collection.
The question and answers you need, to the question you didn't ask:
Q: How do I make this go faster?
A: Several ways:
- Profile: find where the bottleneck is in your program and focus on that. 10% of your code usually consumes 90% of run time.
- Focus on algorithms before you try to optimize implementations. The only thing better than doing an expensive operation 2x as fast is never having to do it. Lazy loading and caching results can be huge time-savers.
- Use one main thread for rendering and user interaction, and do as little real work as possible here. This makes the system appear responsive to users. Rendering should only create new objects when something changes.
- Use a work queue and pool of worker threads for long running tasks especially network requests or disk I/O that would block the rendering and UI thread. All your real work should be asynchronous.
- Generate as little garbage as possible - don't make and destroy objects when you don't need to. Garbage collection should rarely be a significant bottleneck for a Java program.
- Use a single thread for disk I/O, multiple threads in a pool for network I/O, and one worker thread per CPU.
Edit: Before someone complains, async I/O or nonblocking I/O perform better than thread pools for network requests, but they're also more complex for a new developer to use correctly. As long as you're not writing something heavy on networking, a modestly-sized thread pool is enough to saturate a network connection despite latency.
If you're getting noticeable garbage collection pauses, then you're probably doing something wrong. Garbage collection is optimized to get the most results for the least time. Most of the time, GC pauses will be a few milliseconds to do a minor GC (unless we're talking about 4+ GB of heap). Do not explicitly call System.gc() or you'll force unneeded work and a big halt-the-world pause.