It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I heard many times that Java Swing threading model is wrong. I don't fully understand why, I know that the problem is related to the fact that you can draw on a Drawable from another thread other than the main UI thread. I know that there are utility functionalities like SwingUtilities.invokeAndWait and SwingUtilities.invokeLater that let you do your painting in a Runnable, that in turn is run by the Event Dispatcher thread. I guess that this way you ensure that painting is done synchronously and this doesn't leave the buffer in an incosistent state.
My question is: how do "good" UI toolkits behave? What solutions are adopted?
Brian Goetz's Java Concurrency in Practice,
9.1 Why are GUIs single-threaded?:
...In the old days, GUI applications were single-threaded and GUI events
were processed from a “main event loop”. Modern GUI frameworks use a
model that is only slightly different: they create a dedicated event
dispatch thread (EDT) for handling GUI events. Single-threaded GUI
frameworks are not unique to Java; Qt, NextStep, MacOS Cocoa, X
Windows, and many others are also single-threaded. This is not for
lack of trying; there have been many attempts to write multithreaded
GUI frameworks, but because of persistent problems with race
conditions and deadlock, they all eventually arrived at the
single-threaded event queue model in which a dedicated thread fetches
events off a queue and dispatches them to application-defined event
handlers...
For SWT: http://book.javanb.com/swt-the-standard-widget-toolkit/ch05lev1sec7.html
SWT implements a single-threaded user interface model that is typically called apartment threading. In this model, only the user interface thread can invoke user interface operations. This rule is strictly enforced. If you try to access an SWT object from outside the user interface thread, you will get an SWTException("Invalid thread access").
So SWT is single-threaded too. But it takes the extra step to forbid any changes to the UI outside of the UI thread. Consider the alternative in Swing where modifying the UI from somewhere else is allowed but will produce sooner or later unexpected results that will confuse the newbie programmer who will then learn that Swing is single-threaded the "hard" way.
Also, if your design is not clear, you may end up with situations where you think you are in the correct thread but in actuality you are not. You can also be unable to tell reliably what threads will access a specific piece of code, but then you probably have a serious design issue in you own code anyway.
Other than that, I can't imagine other reasons why Swing's threading model would be considered "wrong".
The way current display technologies are implemented, painting pixels on a screen is always serial. You need to generate about 30 images a second, and paint them one by one.
So there is no need for this painting to be multi-threaded, because you would still have to do some synchronization in the background. And this is actually what Swing is doing - it uses a special thread called Event Dispatch Thread to schedule all changes to occur in time before the next image.
So technically, Swing is thread-safe, IF you use the EDT to submit changes. And that's what invokeLater() and invokeAndWait() methods are for. They submit changes to the EDT.
If you don't use EDT and submit some long-running change, such as computing some value after a button press, you can see the application become unresponsive, not repainting itself. Because the EDT is busy doing the calculation for you, and have no time to schedule repaints and other events.
Swing has a thread that is responsible for basically letting the user interact with the graphical portion of your application. If you only perform quick tasks in response to user initiated events, your application will always be responsive.
You might have an issue if you perform a long running task, from an user initiated event, without using a separated thread to run that task - the problem is that, while the task is running, the application will freeze. No repaints will occur, the user will not be able to interact with it all, it will look like the application just locked itself out.
If you are running a task in a separated thread (for example, you are downloading a page and you want to notify the user that the download has completed), then you can't update Swing directly from that task, instead you must use one of the helper methods you mentioned in your question.
It is a more labor-intensive process to create these tasks so that your application is always responsive - but if you are running something that takes a long time (downloading a file is a good example), the application will continue to be responsive even while the task is performed, and you can even let the user cancel the task, just as long as the task itself allows it. You can use a modal dialog to prevent the user from doing anything else while the task is performed (if you want to do so), or have a progress dialog that displays a spinning wheel or something like that. But I guess the important thing is not let the user think that the application just "froze" for no reason.
Related
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I heard many times that Java Swing threading model is wrong. I don't fully understand why, I know that the problem is related to the fact that you can draw on a Drawable from another thread other than the main UI thread. I know that there are utility functionalities like SwingUtilities.invokeAndWait and SwingUtilities.invokeLater that let you do your painting in a Runnable, that in turn is run by the Event Dispatcher thread. I guess that this way you ensure that painting is done synchronously and this doesn't leave the buffer in an incosistent state.
My question is: how do "good" UI toolkits behave? What solutions are adopted?
Brian Goetz's Java Concurrency in Practice,
9.1 Why are GUIs single-threaded?:
...In the old days, GUI applications were single-threaded and GUI events
were processed from a “main event loop”. Modern GUI frameworks use a
model that is only slightly different: they create a dedicated event
dispatch thread (EDT) for handling GUI events. Single-threaded GUI
frameworks are not unique to Java; Qt, NextStep, MacOS Cocoa, X
Windows, and many others are also single-threaded. This is not for
lack of trying; there have been many attempts to write multithreaded
GUI frameworks, but because of persistent problems with race
conditions and deadlock, they all eventually arrived at the
single-threaded event queue model in which a dedicated thread fetches
events off a queue and dispatches them to application-defined event
handlers...
For SWT: http://book.javanb.com/swt-the-standard-widget-toolkit/ch05lev1sec7.html
SWT implements a single-threaded user interface model that is typically called apartment threading. In this model, only the user interface thread can invoke user interface operations. This rule is strictly enforced. If you try to access an SWT object from outside the user interface thread, you will get an SWTException("Invalid thread access").
So SWT is single-threaded too. But it takes the extra step to forbid any changes to the UI outside of the UI thread. Consider the alternative in Swing where modifying the UI from somewhere else is allowed but will produce sooner or later unexpected results that will confuse the newbie programmer who will then learn that Swing is single-threaded the "hard" way.
Also, if your design is not clear, you may end up with situations where you think you are in the correct thread but in actuality you are not. You can also be unable to tell reliably what threads will access a specific piece of code, but then you probably have a serious design issue in you own code anyway.
Other than that, I can't imagine other reasons why Swing's threading model would be considered "wrong".
The way current display technologies are implemented, painting pixels on a screen is always serial. You need to generate about 30 images a second, and paint them one by one.
So there is no need for this painting to be multi-threaded, because you would still have to do some synchronization in the background. And this is actually what Swing is doing - it uses a special thread called Event Dispatch Thread to schedule all changes to occur in time before the next image.
So technically, Swing is thread-safe, IF you use the EDT to submit changes. And that's what invokeLater() and invokeAndWait() methods are for. They submit changes to the EDT.
If you don't use EDT and submit some long-running change, such as computing some value after a button press, you can see the application become unresponsive, not repainting itself. Because the EDT is busy doing the calculation for you, and have no time to schedule repaints and other events.
Swing has a thread that is responsible for basically letting the user interact with the graphical portion of your application. If you only perform quick tasks in response to user initiated events, your application will always be responsive.
You might have an issue if you perform a long running task, from an user initiated event, without using a separated thread to run that task - the problem is that, while the task is running, the application will freeze. No repaints will occur, the user will not be able to interact with it all, it will look like the application just locked itself out.
If you are running a task in a separated thread (for example, you are downloading a page and you want to notify the user that the download has completed), then you can't update Swing directly from that task, instead you must use one of the helper methods you mentioned in your question.
It is a more labor-intensive process to create these tasks so that your application is always responsive - but if you are running something that takes a long time (downloading a file is a good example), the application will continue to be responsive even while the task is performed, and you can even let the user cancel the task, just as long as the task itself allows it. You can use a modal dialog to prevent the user from doing anything else while the task is performed (if you want to do so), or have a progress dialog that displays a spinning wheel or something like that. But I guess the important thing is not let the user think that the application just "froze" for no reason.
I've recently started learning and exploring the basics of GUI programming in Java.
Having been programming for a while I have only done backend work or work and as a result the closest I've gotten to user interfaces is the command console (embarrassing I know).
I'm using Swing and as far as I can gather that means by extension I am also using AWT.
My question is based on this piece of code:
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new frame.setVisible(true);
}
} );
I have been researching this for a while as I wanted to fully understand this strange piece of code and have come across the term 'Event-Dispatching Thread' multiple times. Correct me if I'm wrong but as I understand it; it has to do with using multiple threads and how Java Swing interprets those threads. I gather as well that the above code is used to make sure all the threads are 'safe' before it creates the window, hence the invokeLater?
I have read that:
"You can only call methods that operate on the frame from the Event-Dispatching Thread"
and that only under certain circumstances can you call methods that operate on the frame from the main method.
Can somebody please clarify to me what exactly the Event-Dispatching Thread is?
How it relates to multiple threads of execution and how those threads are not safe to be called from the main method? Also why do we need this invokeLater?
Can we not just create the window as any other object?
I've hit a bit of a road block in my research as I'm not grasping these relations and ideas.
A side note is that I like to base my knowledge on in-depth understanding as I believe this leads to the best overall outcome and as a result the best programs. If I understand in-depth how something works then you can use the tips and tweaks effectively rather than just parroting them back in to code, so please don't be afraid to give me some extra in-depth explanations and broaden my knowledge.
Thank you.
The event dispatch thread is a special thread that is managed by AWT. Basically, it is a thread that runs in an infinite loop, processing events.
The java.awt.EventQueue.invokeLater and javax.swing.SwingUtilities.invokeLater methods are a way to provide code that will run on the event queue. Writing a UI framework that is safe in a multithreading environment is very difficult so the AWT authors decided that they would only allow operations on GUI objects to occur on a single special thread. All event handlers will execute on this thread and all code that modifies the GUI should also operate on this thread.
Now AWT does not usually check that you are not issuing GUI commands from another thread (The WPF framework for C# does do this), meaning it's possible to write a lot of code and be pretty much agnostic to this and not run into any problems. But this can lead to undefined behavior, so the best thing to do, is to always ensure that GUI code runs on the event dispatch thread. invokeLater provides a mechanism to do this.
A classic example is that you need to run a long running operation like downloading a file. So you launch a thread to perform this action then, when it is completed, you use invokeLater to update the UI. If you didn't use invokeLater and instead you just updated the UI directly, you might have a race condition and undefined behavior could occur.
Wikipedia has more information
Also, if you are curious why the AWT authors don't just make the toolkit multithreaded, here is a good article.
EventDispatchThread (EDT) is special thread reserved only for Swing GUI and *Swing's related events e.g. create/change/update Swing JComponents, more for asked questions here and here
all output to the GUI from BackGround Tasks, Runnable#Thread must be wrapped into invokeLater(), from synchronized Objects into invokeAndWait();
I am currently learning Swing, and I am new to GUI development in general. In my test application, I have multiple event listners for a single event source, and I am wondering which one of these event listeners will be excecuted first.
Also, I am curious to know how Swing event-handling works in a single-threaded environment, especially when you have multiple listeners for a single event source.
Lastly, I would like to know some common cases where I have to use multiple threads in Swing.
Thanks!
I will try to answer all 3 of your questions. First of all, the order that the ActionListeners fire is not specified. One should never assume a specific order that they will fire. If you need actions to take place in a specific order, put them in the same ActionListener.
When programming Swing, you will 'almost' always be in a multi-threaded environment. There is one thread called the Event Dispatch Thread (EDT). This is the thread that handles all events. Any other processing you do should be done on a different thread, otherwise your Swing GUI can become unresponsive.
A common case for multiple threads in Swing is any time you need to do some processing that takes an extended amount of time. (Intense calculations, IO, database connections) You will want to do the hard work on a separate thread from the EDT. That will keep your GUI responsive.
The Oracle network has a great tutorial on concurrency in Swing. I recommend you check it out.
A Swing programmer deals with the following kinds of threads:
Initial threads, the threads that execute initial application code.
The event dispatch thread, where all event-handling code is executed. Most code that interacts with the Swing framework must also execute on this thread.
Worker threads, also known as background threads, where time-consuming background tasks are executed.
The canonical answer to any multi-threading questions in Swing is to use a SwingWorker. It allows you to easily coordinate background work on a separate thread with the EDT. As usual, Oracle has a great tutorial on how to use SwingWorker.
I know what "thread" means and if I understand the event dispatching thread (EDT) as
"just a thread", it explains a lot but, apparently, it does not explain everything.
I do not understand what is special about this thread. For example I do not understand why we should start a GUI in a the EDT? Why the "main" thread is bed for GUI? Well, if we just do not want to occupy the main thread why we cannot start GUI just in "another thread" why it should be some "special" thread called EDT?
Then I do not understand why we cannot start the EDT like any other thread? Why we should use some special tool (called invokeLater). And why GUI, unlike any other thread, does not start immediately. We should wait until it is ready to accept our job. Is it because EDT can, potentially execute several task simultaneously?
If you decide to answer this question, could you pleas use a really simple terminology because otherwise, I am afraid, I will not be able to understand the answer.
ADDED:
I always thought that we have one "task" per thread. So, in every thread we execute a predefined sequence of commands. But it seems to me that in the event dispatching thread we can have sever task. Well, they are not executed simultaneously (thread switches between different task but there are still several task in one thread). Is it right? For example there is one thread in the EDT which display the main window, and then additionally to that we sent to the EDT another task which should update one of the window components and EDT will execute this new task whenever it is ready. Is EDT differ from other threads in this way?
The event dispatching thread is the thread that handles all GUI events and manages your Swing GUI. It is started somewhere in the Swing code if you have any GUI in your program. The reason it is done behind the scenes is because of simplicity - you do not have to bother with starting and managing an extra thread by yourself.
Regarding the fact that you have to update your GUI with invokeLater() it is because of concurrency issues. The GUI can be modified only from one thread because Swing is not thread safe(it is worth to note that most of toolkits are not thread safe, there is a nice article that gives some ideas why). This is why you have to submit all GUI updates to run on EDT.
You can read more on concurrency in Swing and event dispatching thread in Sun tutorial on concurrency in Swing. Also, if you would like to see how this could be done in a different way you might like to check out SWT toolkit. In SWT you have to manage EDT by yourself.
I always thought that we have one
"task" per thread. So, in every thread
we execute a predefined sequence of
commands. But it seems to me that in
the event dispatching thread we can
have sever task. Well, they are not
executed simultaneously (thread
switches between different task but
there are still several task in one
thread). Is it right? For example
there is one thread in the EDT which
display the main window, and then
additionally to that we sent to the
EDT another task which should update
one of the window components and EDT
will execute this new task whenever it
is ready. Is EDT differ from other
threads in this way?
No, the EDT is not fundamentally different from other threads. And "task" is not a good word to use, because it could be confused with OS-level processes (which are also often called task). Better use Runnable, the interface used to give code to the EDT to execute via invokeLater().
The EDT is basically connected to a queue of things it has to do. When the user clicks a button on the GUI, a Runnable that notifies all listeners attached to the button goes into the queue. When a window is resized, a Runnable doing revalidate&repaint goes into the queue. And when you use invokeLater(), your Runnable goes into the queue.
The EDT simply runs an endless loop that says "take a Runnable from the queue (and if it's empty sleep until you're notified that it's not) and execute it.
Thus, it executes all those little Runnable pieces of code one after another, so that each of them basically has the GUI all to itself while it runs, and doesn't have to worry about synchronizing anything. When you manipulate the GUI from another thread, this assumption is broken, and you can end up with the GUI in a corrupted state.
What is the EDT?
It's a hacky workaround around the great many concurrency issues that the Swing API has ;)
Seriously, a lot of Swing components are not "thread safe" (some famous programmers went as far as calling Swing "thread hostile"). By having a unique thread where all updates are made to this thread-hostile components you're dodging a lot of potential concurrency issues. In addition to that, you're also guaranteed that it shall run the Runnable that you pass through it using invokeLater in a sequential order.
Note that it's not just that you're dodging the concurrency issue: you must respect Sun's guidelines regarding what must and what must not be done on the EDT or you'll have serious problems in your application.
Another benefit is that some Swing components tend to throw unwanted exceptions and when this happen they're automagically dealt with and won't crash the EDT (AFAIK if you really manage to kill the EDT it is automagically restarted).
In other words: you don't have to deal with all the broken Swing components and the exceptions they throw yourself: the EDT is taking care of that (just take a look at the countless Swing bugs throwing exceptions in Sun's bug parade, it's fascinating... And yet most apps keep working normally).
Also, by doing only what's mandatory in the EDT allows the GUI of your app to stay "responsive" even tough there may be tasks running in the background.
The important thing to remember is that Swing classes are not thread-safe. This means that you always should call Swing methods from the same thread, or you risk getting weird or undefined behavior.
So the solution: only call Swing methods from a single thread. This is the EDT thread - it's not special in any way other than that it is the thread designated to call swing methods from.
Now you may ask why are Swing methods not thread safe? After several unsuccessful attempts, GUI toolkit designers discovered that it's inherently impossible to design a thread-safe GUI toolkit. Too often events are passed in opposite directions (input events from bottom to top, application events from top to bottom) which always leads to deadlocks. So that's just the way it is.
I've often heard criticism of the lack of thread safety in the Swing libraries. Yet, I am not sure as to what I would be doing in my own code with could cause issues:
In what situations does the fact Swing is not thread safe come into play ?
What should I actively avoid doing ?
Never do long running tasks in response to a button, event, etc as these are on the event thread. If you block the event thread, the ENTIRE GUI will be completely unresponsive resulting in REALLY pissed off users. This is why Swing seems slow and crusty.
Use Threads, Executors, and SwingWorker to run tasks NOT ON THE EDT ( event dispatch thread).
Do not update or create widgets outside of the EDT. Just about the only call you can do outside of the EDT is Component.repaint(). Use SwingUtilitis.invokeLater to ensure certain code executes on the EDT.
Use EDT Debug Techniques and a smart look and feel (like Substance, which checks for EDT violation)
If you follow these rules, Swing can make some very attractive and RESPONSIVE GUIs
An example of some REALLY awesome Swing UI work: Palantir Technologies. Note: I DO NOT work for them, just an example of awesome swing. Shame no public demo... Their blog is good too, sparse, but good
This is one of those questions that makes me glad I purchased Robinson & Vorobiev's book on Swing.
Anything that accesses the state of a java.awt.Component should be run inside the EDT, with three exceptions: anything specifically documented as thread-safe, such as repaint(), revalidate(), and invalidate(); any Component in a UI that has not yet been realized; and any Component in an Applet before that Applet's start() has been called.
Methods specially made thread-safe are so uncommon that it's often sufficient to simply remember the ones that are; you can also usually get away with assuming there are no such methods (it's perfectly safe to wrap a repaint call in a SwingWorker, for example).
Realized means that the Component is either a top-level container (like JFrame) on which any of setVisible(true), show(), or pack() has been called, or it has been added to a realized Component. This means it's perfectly fine to build your UI in the main() method, as many tutorial examples do, since they don't call setVisible(true) on the top-level container until every Component has been added to it, fonts and borders configured, etc.
For similar reasons, it's perfectly safe to build your applet UI in its init() method, and then call start() after it's all built.
Wrapping subsequent Component changes in Runnables to send to invokeLater() becomes easy to get right after doing it only a few times. The one thing I find annoying is reading the state of a Component (say, someTextField.getText()) from another thread. Technically, this has to be wrapped in invokeLater(), too; in practice, it can make the code ugly fast, and I often don't bother, or I'm careful to grab that information at initial event handling time (typically the right time to do it in most cases anyway).
It's not just that Swing is not thread-safe (not much is), but it's thread-hostile. If you start doing Swing stuff on a single thread (other than the EDT), then when in cases where Swing switches to the EDT (not documented) there may well be thread-safety issues. Even Swing text which aims to be thread-safe, isn't usefully thread-safe (for instance, to append to a document you first need to find the length, which might change before the insert).
So, do all Swing manipulations on the EDT. Note the EDT is not the thread the main is called on, so start your (simple) Swing applications like this boilerplate:
class MyApp {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
runEDT();
}});
}
private static void runEDT() {
assert java.awt.EventQueue.isDispatchThread();
...
An alternative to using intelligent skins like substance is to create the following utility method:
public final static void checkOnEventDispatchThread() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new RuntimeException("This method can only be run on the EDT");
}
}
Call it in every method you write that is required to be on the event dispatch thread. An advantage of this would be to disable and enable system wide checks very quickly, eg possibly removing this in production.
Note intelligent skins can of course provide additional coverage as well as just this.
Actively avoid doing any Swing work at all except on the event dispatching thread. Swing was written to be easy to extend and Sun decided a single-threaded model was better for this.
I have had no issues whilst following my advice above. There are some circumstances where you can 'swing' from other threads but I've never found the need.
If you're using Java 6 then SwingWorker is definately the easiest way to deal with this.
Basically you want to make sure that anything that changes a UI is performed on the EventDispatchThread.
This can be found by using the SwingUtilities.isEventDispatchThread() method to tell you if you are in it (generally not a good idea - you should know what thread is active).
If you aren't on the EDT then you use SwingUtilities.invokeLater() and SwingUtilities.invokeAndWait() to invoke a Runnable on the EDT.
If you update UI's not on the EDT you get some incredibly strange behaviour. Personally I don't consider this a flaw of Swing, you get some nice efficiency by not having to synchronize all of the threads to provide a UI update - you just need to remember that caveat.
The phrase 'thread-unsafe' sounds like there is something inherently bad (you know... 'safe' - good; 'unsafe' - bad). The reality is that thread safety comes at a cost - threadsafe objects are often way more complex to implement (and Swing is complex enough even as it is.)
Also, thread-safety is achieved either using locking (slow) or compare-and-swap (complex) strategies. Given that the GUI interfaces with humans, which tend to be unpredictable and difficult to synchronize, many toolkits have decided to channel all events through a single event pump. This is true for Windows, Swing, SWT, GTK and probably others. Actually I don't know a single GUI toolkit which is truly thread-safe (meaning that you can manipulate its objects' internal state from any thread).
What is usually done instead is that the GUIs provide a way to cope with the thread-unsafety. As others noted, Swing has always provided the somewhat simplistic SwingUtilities.invokeLater(). Java 6 includes the excellent SwingWorker (available for previous versions from Swinglabs.org). There are also third party libraries like Foxtrot for managing threads in Swing context.
The notoriety of Swing is because the designers have taken light handed approach of assuming that the developer will do the right thing and not stall the EDT or modify components from outside the EDT. They have stated their threading policy loud and clear and it's up to the developers to follow it.
It's trivial to make each swing API to post a job to the EDT for each property-set, invalidate, etc., which would make it threadsafe, but at the cost of massive slowdowns. You can even do it yourself using AOP. For comparison, SWT throws exceptions when a component is accessed from a wrong thread.
Here's a pattern for makng swing thread-freindly.
Sublass Action (MyAction) and make it's doAction threaded.
Make the constructor take a String NAME.
Give it an abstract actionImpl() method.
Let it look like.. (pseudocode warning!)
doAction(){
new Thread(){
public void run(){
//kick off thread to do actionImpl().
actionImpl();
MyAction.this.interrupt();
}.start(); // use a worker pool if you care about garbage.
try {
sleep(300);
Go to a busy cursor
sleep(600);
Show a busy dialog(Name) // name comes in handy here
} catch( interrupted exception){
show normal cursor
}
You can record the time taken for the task, and next time, your dialog can show a decent estimate.
If you want to be really nice, do the sleeping in another worker thread too.
Note that not even the model interfaces are thread safe. The size and the content are queried with separate get methods and so there is no way of synchronizing those.
Updating the state of the model from another thread allows for it to at least paint a situation where size is still bigger (table row is still in place), but the content is no longer there.
Updating state of the model always in EDT avoids these.
invokeLater() and invokeAndWait() really MUST be used when you are doing any interaction with GUI components from any thread that is NOT the EDT.
It may work during development, but like most concurrent bugs, you'll start to see weird exceptions come up that seem completely unrelated, and occur non-deterministly - usually spotted AFTER you've shipped by real users. Not good.
Also, you've got no confidence that your app will continue to work on future CPUs with more and more cores - which are more prone to encountering weird threading issues due to them being truely concurrent rather than just simulated by the OS.
Yes, it gets ugly wrapping every method call back into the EDT in a Runnable instance, but that's Java for you. Until we get closures, you just have to live with it.
For more details about threading, Taming Java Threads by Allen Holub is an older book but a great read.
Holub, really promotes responsive UI and details examples and how to alleviate problems.
http://www.amazon.com/Taming-Java-Threads-Allen-Holub/dp/1893115100
http://www.holub.com/software/taming.java.threads.html
Love the "If i was king" section in the end there.