The Black Art of Threading
By Bruce Eckel
Threading is like stepping into an entirely new world and learning a whole new programming language, or at least a new set of language concepts. Although support for threads can make Java seem more complicated, don't blame the language threads are tricky.
One of the main difficulties with threads occurs because more than one thread may be sharing a resource, like the memory in an object, and you must ensure that multiple threads don't simultaneously try to read and change that resource. This requires judicious use of Java's synchronized keyword, a very helpful tool that must be understood thoroughly, as it can quietly introduce deadlock situations (for a complete introduction to synchronized and threading issues, see "Thinking in Java" at www.EckelObjects.com/Eckel).
A significant, nonintuitive issue in threading is that, because of thread scheduling, you can typically make your applications run faster by inserting calls to sleep() inside run()'s main loop. This definitely makes it feel like an art, in particular when the longer delays seem to speed up performance. Of course, the reason this happens is that shorter delays can cause a sleep() scheduler interrupt before the running thread is ready to go to sleep, thus forcing the scheduler to stop, and later restart it so it can finish what it was doing and then go to sleep. It takes extra thought to realize how messy things can get.
Java is designed to allow you to create as many objects as you need to solve your problem.