I have an object that implements Runnable and I create a new thread with this object by pressing a button on my Swing form. The thread does some stuff in the background and then updates my Swing form through the AWT Event Queue. I don't ever need to create multiple threads that run simultaneously, only one at a time. If I click the button multiple times very fast it will of course create multiple threads and it causes some problems with unsynchronized updates. So I am thinking I can lock the button and wait for the thread to finish before it can be pressed again or prevent new threads from being created until the previous ones are done.
I really don't need to created multiple threads that wait for one another, so locking the button would be fine.
Should I implement both in case later I don't want to lock the button? Is locking a button acceptable or is it bad programming practice?
Creating a SIngle threaded pool will create a single thread that waits for runnables to appear on a queue. You submit your runnable to the queue, and it will execute it and go back to wait for the next runnable.
It works, but I still had to synchronize some methods to prevent the same NPE, but what I have is that each SingleThreadExecutor thread invokes the AWT Event Queue with a new runnable that access the same ArrayList to read values as the SingleThreadExecutor thread, which it is invoked from, writes too.
So it appears as soon as the SingleThreadExecutor calls the AWT Event Queue, which is the last call in the thread, the thread is considered done. I wasn't taking that into consideration.
If your thread is writing to your array list and event handler is reading from it, you will have to protect the list. Event handler is called on an event queue thread that is started By java.
Remember that synchronized list will only synchronize on individual method calls, not across calls. So, if for example, you are iterating over list, you will need to synchronize yourself. Also, remember that the list won't protect the objects inside the list. So, if your background thread gets an object from the list and starts modifying it, the synchronized list won't protect you because the call to the objects will be outside the list's methods. You will have to protect those calls yourself
A little advanced concepts in case you are worried about contention between the 2 threads: depending on how long you lock the list, you might run into problems where the UI freezes while the runnable is executing.
What are you doing in the background thread? If your runnable is very light, like let's say it only adds an element to the list, you might want to take a look at copyonwritearraylist. It makes a copy of the list every time you modify it. It's been a while since I've used it, but I think it will work well if number of changes to the list are much lower than number of times the list is read
OTH, if you build the list completely in your runnable, then consider double buffering. Keep one list for reading; awt event queue will use it. In your runnable create a new list and populate it. After you populate it, simply switch the 2 lists; the list that your runnable created becomes the list that awt event queue will use. This way you will only need to put a lock when you switch the lists, not when you are operating on the list. This reduces the amount of contention to almost nothing.
I am going through a list of words in the background thread and using regex to match all cases in a text file of the words, then highlighting them. It is very inefficient for this I know (O(n^2) ), and it takes about 30 or 40 seconds to do a text file the size of a book like "Through the Looking Glass", but for now I am doing it this way and then I will switch to using a hash table and my own string matching so it is fast. Anyway, as I match the words, I update a counter and I update an ArrayList that holds the indexes for the highlighting. When done, I invoke the AWT Event Queue with a worker that updates the Swing form with the count and paints the highlighting on the JTextArea text using the index ArrayList for each start and stop point.
I was thinking of using 2 lists, but I think just synchronizing the 2 read & write methods is efficient. I actually don't even need the executor and I have no NPEs if I just synchronize the 2 methods for now. I may get into a situation later where I want to make a copy.