aspose file tools*
The moose likes Threads and Synchronization and the fly likes Thread waiting for another thread Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Java » Threads and Synchronization
Bookmark "Thread waiting for another thread" Watch "Thread waiting for another thread" New topic
Author

Thread waiting for another thread

ulvi ugur
Ranch Hand

Joined: Aug 05, 2003
Posts: 46
Hi All,

I am using an API to get some streaming data from a server. It has self-explanatory classes like DataClient, Session, Connection, etc. The implementation class implements DataClient which should initiate Session and Connection objects. When required calls are in a main method, it would look like this



The problem with this code is, conn.connect(); method does not block the main thread until the connection is established, so when the client does registerInterest(), it throws exceptions that the connection is not there yet.

Luckily, ConnectionImpl actually implements Connection which has a processEvent(Event e) method, which is called when the connection is up. Ideally, I need to "suspend" the main thread and resume it using processEvent method.

So, my question is how I can make the main class wait until the connection is established ?< One can surely use things like Thread.sleep(timeout) which I don't find elegant.

As far as I understand wait() / notify() is used for the instances of the class which is not the case here (or is it ?)

I looked into CyclicBarrier as well but it als seems like the are usable again for the instances of the same class.

Any ideas how an elegant design of this problem should look like ? I hope my description was not complicated and thanks in advance for your help.

Regards,

Ulvi
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18659
    
    8

The way to wait for a thread to complete its work is to call that thread's join() method. Nothing more than that.

However your application doesn't appear to have access to the thread which that ConnectionImpl is using. So perhaps there's a method in ConnectionImpl which waits for the connection to become available? If not, perhaps you could add such a method?
ulvi ugur
Ranch Hand

Joined: Aug 05, 2003
Posts: 46
Hi Paul,

Thanks for your reply. It might be an interesting idea to use join() but I can't figure out how. As far as I understand, join() has a connection with run(), meaning main thread can be blocked with t.join() until the job in run() is completed.

IMHO could more apply for a "Worker" scenario. But a connection is not a synchronous event, and whatever I do in run() of this additional thread, connection event will always be thrown in processEvent(Event e) method.

Can't figure out how I can sort this out with join(), any example you can post ? Or did you mean something different ?

Thanks in advance,

Ulvi
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4181
    
  21

Originally posted by ulvi ugur:
Hi Paul,

Thanks for your reply. It might be an interesting idea to use join() but I can't figure out how. As far as I understand, join() has a connection with run(), meaning main thread can be blocked with t.join() until the job in run() is completed.

IMHO could more apply for a "Worker" scenario. But a connection is not a synchronous event, and whatever I do in run() of this additional thread, connection event will always be thrown in processEvent(Event e) method.

Can't figure out how I can sort this out with join(), any example you can post ? Or did you mean something different ?

Thanks in advance,

Ulvi


From the sounds of it, it looks like the API was designed for you to create the connection and be done. Then use the processEvent(Event e) method of whatever listener to continue doing work. You may find it easier to move the code into that event method rather than where you have it. You should read up on what thread the processEvent(Event e) method gets executed in, though. If your work is time consuming you don't want to block GUI/streaming functionality, and so might want to start a new thread to do the work.

Another option, though a little out of the way, would be to use a BlockingQueue (maybe a SynchronousQueue?). You make the BlockingQueue, start the connection then try to take() some token (any non-null) from the Queue, which will block until there is something to take. Then make your processEvent(Event e) method put() the token into the Queue when the connection is complete. This keeps your main thread waiting until the connection is done, and your processEvent(Event e) method call short and sweet - freeing up that thread for any other work. This is basically just re-dispatching the event from whatever dispatcher thread processEvent gets called in back to the main thread.


Steve
ulvi ugur
Ranch Hand

Joined: Aug 05, 2003
Posts: 46
Hi Steve,

Thanks for your comments.

From the sounds of it, it looks like the API was designed for you to create the connection and be done. Then use the processEvent(Event e) method of whatever listener to continue doing work. You may find it easier to move the code into that event method rather than where you have it. You should read up on what thread the processEvent(Event e) method gets executed in, though. If your work is time consuming you don't want to block GUI/streaming functionality, and so might want to start a new thread to do the work.

--> I could do this theoritically but it would not be a clear design to me as the main thread would initiate the connection and not have a clear function call series. I would prefer a sequence in the main thread like :

connect();
subscribe();
collectdata();
processdata();

Your second idea might be a good idea although I think it is a sidekick. To be honest, I probably expected to find a better solution, somehow.
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4181
    
  21

Originally posted by ulvi ugur:
Hi Steve,

Thanks for your comments.


--> I could do this theoritically but it would not be a clear design to me as the main thread would initiate the connection and not have a clear function call series. I would prefer a sequence in the main thread like :

connect();
subscribe();
collectdata();
processdata();

Your second idea might be a good idea although I think it is a sidekick. To be honest, I probably expected to find a better solution, somehow.


The problem with this sequence is that it doesn't seem to follow the strategy the API proposes. The API you are using provides an event-driven system. So you are best off using the event system the API provides, running the code that is supposed to happen when specific events occur in the handler for those events - it is like a SAX parser for XML. Remember that you can still have the code centralized in a particular class, and even force execution of that code in the same main thread. The only difference is that the Event drives the code execution order, not a linear sequence of methods.
ulvi ugur
Ranch Hand

Joined: Aug 05, 2003
Posts: 46
Hi Steve,

Thanks for your reply.

As you mentioned, API surely based on an event model. This actually is the challange; creating a snapshot from an event-driven model.

Your second idea inspired me and I came up with a class like :



I used this object as :



where blocker object is just a dummy object and tmpTimeout is the timeout for the operation. This allowed me to block the main thread until a task s completed (connection event or data completed event-->unblock()) or the timeout is hit-->TimerTask.

Do you see any potential problems with this design ?
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4181
    
  21

I do see a problem with the code you have. The main thing is that the object won't be thread safe - which is dangerous since the whole point of the object is to play in a threaded environment.

Imaging this:
MainThread -> calls ThreadBlocker.block() on its own blocker object.
ProcessThread -> calls ThreadBlocker.block() on its own blocker object.
EventDispatcher -> calls ThreadBlocker.unblock().

The unblock will release the block() on ProcessThread, and the MainThread is left to timeout. What if the unblock event was triggered by the connection getting ready - which should trigger the MainThread, but the ProcessThread is waiting on some other object it needs to work on. Now the ProcessThread has spuriously awoken on the wrong notify and the MainThread lingers on because it can't get notified properly.

You might be tempted to use the same blocker for all your threads, but then again you are going to spuriously wake up the ProcessThread (or the MainThread) when its conditions aren't met.

A better solution would be to provide the object to notify on as an argument to both the block() and unblock() methods, or provide some key to a map where proper locks can be maintained for separate signalling conditions.

Another addition concern would be why are you implementing a timeout timer task when all you need to do is specify a timeout for the wait command?


Finally, the method provided doesn't give any hint as to how the wait ended. Was it interrupted? Did a timeout occur? Or did it end normally? This is all important information for you to determine what the next step should be in your code - do you have to try to re-make the connection? Do you have to give up and tell the user of an error? Or can you process normally? I generally don't like catching exceptions inside utility methods like this because it hides the results from the caller, and injects your logging mechanism into the utility, which makes it hared to re-use. The InterruptedException can be useful, so pass it along by throwing it again and let the caller figure out how to deal with an interrupt.

Since neither your timer idea, or the wait(timeout) mechanism provide feedback on if the timeout is what caused the wake-up, and because I like the different conditioning and locking tools available in the java.util.concurrent.locks package, I would probably make something along the lines of:


I could call it like:


By caching the Conditions used for waiting on and passing in the Lock for both the waitOn and wakeUp methods, I can safely get multiple threads blocking on different conditions and not worry about waking the wrong one. (this still smells a bit to me, I am not sure what I am doing wrong when storing the Lock/Conditions...). You don't have to pass in the lock and map lock -> conditions. You could pass in some Enum, or String constant, for example, as a command key which you could pull the proper Lock and Condition for.

The boolean return value lets me know if a timeout occurred. The InterruptedException is now caught in a place I am more likely to know what to do about it, or at least how to log it properly.

And I know I am reiterating myself here, but would probably really just go back and work inside the event dispatch mechanism... seems cleaner, but if you don't want to, I guess I can understand how you would be more comfortable with this more procedural type of design.
[ October 24, 2008: Message edited by: Steve Luke ]
ulvi ugur
Ranch Hand

Joined: Aug 05, 2003
Posts: 46
Hi Steve,

You are absolutely right about this wait(long) advice; timertask was one of my brainstorming ideas which does not make much sense with wait(long).

On the other hand, naturally you are still thinking in "continuous process" terms which is great but probably is an overkill for my situation here. I just replaced the timertask with wait(timeout). So I call it as :



I have the ThreadBlocker.block() only twice in the lifetime of the application and they are both limited with time. I have the unblock() method in respective processEvent() calls, in case connection and connection of data are successful which lets the thread continue before timeout is expired. Your concerns probably would apply for an ongoing subscription/processData workflow but what I have is a waterfall pattern. i.e. if connection doesn't work, I don't try again, if data is not there for a certain amount of time, I don't try again either. In real life both of these are probably operational issues (in very unlikely case) which need to be resolved first.

To summarize, for my current purpose, I have a solution. If I really had a continuous process of pub/sub, event dispatch model would probably help me even more.

Steve, thank you very much. Your help was very much appreciated.

Best Regards,

Ulvi
Anton Golovin
Ranch Hand

Joined: Jul 02, 2004
Posts: 476
Ulvi, join() is the way you wait on a thread in Java. Interesting or not, this is the only way.


Anton Golovin (anton.golovin@gmail.com) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4181
    
  21

Originally posted by Anton Golovin:
Ulvi, join() is the way you wait on a thread in Java. Interesting or not, this is the only way.


Hi Anton, the problem with join is that the other thread has to finish before the join completes. In Ulvi's situation the other thread has to continue processing, and the main thread just needs to be aware of when certain events take place. So join isn't the appropriate tool, either event dispatching or synchronized notices is.
Anton Golovin
Ranch Hand

Joined: Jul 02, 2004
Posts: 476
Originally posted by Steve Luke:


Hi Anton, the problem with join is that the other thread has to finish before the join completes. In Ulvi's situation the other thread has to continue processing, and the main thread just needs to be aware of when certain events take place. So join isn't the appropriate tool, either event dispatching or synchronized notices is.


Well, a central EventController class that wakes up threads would work here.
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: Thread waiting for another thread