I have observed an odd problem while working on threads. Let me first explain.
My application queues up queries and each are run one-by-one. Since, the GUI should be responsive while running the queries, I have made 3 external threads.
Handler - Takes care of running the query and displaying the results when it receives it. This is done so that the GUI thread can continue accepting new queries.
Querier - This thread is the one that actually runs the queries. This thread uses a parameter object to get the query, statement and other flags needed for the execution. This gets started by the Handler thread once there is a statement object (in my case as prepared-statement object)
Canceller - This thread is used to cancel the running statement in the Querier thread.
I have my own debug statements to find out how exactly the threads are working. The problem arises while simple execution. When I run, say 3 queries, one after the other there is no problem. Each one executes properly, and the output gets displayed properly. Same is the case if 2 queries are queued up. However, for 3 queued up queries, according to the timing, I get strange results.
3 queries queued up
In this case, first query runs and results are displayed properly. For the 2nd and 3rd queries however, the outputs are the duplicated even though the conditions are different. So, if I'm searching for records with field = a and field = b, both my 2nd and 3rd query would show results with field =a.
1st query has finished, 2 and 3rd are queued
Here, by the time I queued the 3rd query, the 1st one has completed. In this case, the 2nd query's Handler starts, but it runs the 3rd query's Querier.
As I have mentioned, I pass all the required objects(prepared-statement,start and cancel flags) in a Parameter Object. But I cannot fathom why my program is giving me weird results. Can anyone help me?
Sounds like the kind of thing that happens when you've got static variables that shouldn't be static. That, or you're assuming somewhere that an object is being copied when it's actually not. Does this ring any bells?
Each query has its own Parameter Object. There are no static variables, except final static variables. Let me show you the debug listing I have created.
INSERT NEW QUERY -- New Query queued START Handler: ELECTRIC -- Query title is ELECTRIC IN getResultSet(),waiting: ELECTRIC -- Handler waiting for resultset START Querier: ELECTRIC -- Query execution started IN Querier, serviced: ELECTRIC -- Query execution completed END Querier: ELECTRIC -- Querier exits IN getResultSet(),notified: ELECTRIC -- Handler gets notified IN HandlerThread: Received ResultSet, ELECTRIC query END Handler: ELECTRIC -- Handler exits DELETE
Here is the debug statements for the problem where the 2nd query runs the querier of the 3rd.
START Handler: SUBSCRIBER IN getResultSet(),waiting: TELEPHONE START Querier: TELEPHONE IN Querier, serviced: TELEPHONE END Querier: TELEPHONE IN getResultSet(),notified: TELEPHONE IN HandlerThread: Received ResultSet, SUBSCRIBER query END Handler: SUBSCRIBER DELETE
As you can see, although SUBSCRIBER query handler has started, it is the Querier for TELEPHONE which is running and it is that result which is getting displayed. Let me remind you, that the code is such that the Querier is started by the Handler, handler waits for the querier to get a resultset.
Some more interesting facts.
Since this is an enhancement for existing code that I'm doing, I did not have the luxury of coding from scratch to a particular design. The code i had to write was far from elegant. The Handler is started in one class, a reference is passed to another class and there the Querier is started. But since my one-off queries are running straight, I believe that my code is running properly.
Thread calling Thread
The Handler class extends thread and inside this class is a function which starts the Querier thread.
I can't say if this is where the problem is. I've just mentioned it so you might get a better picture.
Remember that when you've eliminated all the possibilities, something impossible must have happened. In other words, debugging is usually about finding out something you think is true is actually not. Somewhere there is crosstalk between threads, and that has to be coming from a shared variable somewhere. Statics are one possibility, inadvertently shared objects are another; there are certainly other, less likely possibilities -- like overwriting a common disk file, for instance. But it's going to be something like this. Don't worry about the threads so much, except to worry about cases where two threads might both be accessing the same data. Are there assumptions being made that X happens before Y -- for example, that some data is copied before some thread actually starts? In this case, you might be looking at a synchronization problem, although it actually sounds backwards from what I'd expect in that case.