David Jeske was kind enough to point out the following:
I didn't see any mention of one of the problems which I find
most tricky to deal with in Swing. You talk about how it's important
to use invokeLater (or other techniques) to assure that the UI is
only changed in the UI thread, however, you didn't seem to
acknowledge the effects this has on your CustomTableModel.
The way your custom table model is designed, addMail and removeMail
should only be called from the foreground thread, because they
immediately change the underlying table model data. It's not valid to
change the table model data outside of the UI thread, because the
JTable could be in the middle of an existing paint request.
This error is seldom seen in practice when adding elements to a table
model, because the JTable still thinks there are fewer items in the
list. The new item is simply ignored until it sees the
tablerowsinserted notification. However, this is critical when
removing rows, because the JTable could be in the middle of a paint.
Here is an example: When removing row "3", JTable might fetch
information for rows 3-6 during a paint. Since you already removed
row 3 in another thread, you would return what formerly was 4-7. Then
when you tell it row 3 is deleted, it removes the information for
what is actually row 4, and while it thinks that it has 4-6, it
actually has 5-7. The real row 4 is mysteriously gone, and when it
asks for row 7 to repaint a new bottom row on the screen, there will
be two copies of row 7.
This is not the only race condition but it is one of the more common
ones. I think you're writeup would be more complete if it made at
least some mention of these issues.
Thanks for the great article!