wood burning stoves 2.0*
The moose likes Threads and Synchronization and the fly likes Clarifying Synchronize(object) (RESOLVED) Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Java » Threads and Synchronization
Bookmark "Clarifying Synchronize(object) (RESOLVED)" Watch "Clarifying Synchronize(object) (RESOLVED)" New topic
Author

Clarifying Synchronize(object) (RESOLVED)

Alvin Parker
Ranch Hand

Joined: Oct 01, 2013
Posts: 38
In the past, I've used Threads to execute some task at intervals or to accept Socket Connections and so forth.

I have reason now to build a threaded server with a thread pool implementation. I'm using the concurrency packages for that.

Most of my threads will get data from a controller which is initialized and holds reference to a model at the time the server starts. The model's data is mostly static but when it does change, I need all the other threads in the thread pool to not process until the models are all updated with whatever new data they are getting.

I want to block all the client threads in the simplest and safest way possible. There is a lot of info on the web about this and I'm just a little tenous as I know that getting this wrong could have disasterouse effects in the program and those effects may not be seen until it's too late and has caused a serious problem.

If my controller is used by both my client Threads and my DB worker Thread (all coming from the same thread pool managed by the concurrency package), whenever a thread needs to lock for the models to update, am I correct in assuming that if I just do the following represented by skeleton code, I'll be fine...

//server socket


That's my mock server's skeleton code. Now to the managing object.



Is it as simple as that to be sure that no one can c.getData() while data is being updated or do I need to do more to be sure I'm safe?


Thanks. I know this is a topic for lots of discussion and I've read much of that but given all the cautions, I want to be absolutely sure that there is no way a Map in my model is updated by two Threads at the same time and no way for Threads to get data while the model is being updated. If it's as simple as just synchronize(objectToLock), then why all the hand wringing and why don't people just use that instead of trying to manage calling wait() and notify() which seems dangerous to me? However, I see lots of people suggesting that approach which is one of the reasons I'm reticent to just use sychronize(object).

Thanks for imparting your wisdom and experience to me.

Cheers!
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4167
    
  21

No, that won't work at all. You are creating the synchronized block in the thread which is distributing the task, not the thread which runs the task. As soon as the task is submitted, NOT when it is run, the lock will be released.

You need to put all your tasks into a lockable condition. The best bet for this is a ReadWriteLock. This is a high level lock mechanism that allows all reads to happen without blocking each other, but a write option blocks all other writes, and all reads from happening. This would need to be done in the run() method that is to be executed. It should know if it is a write command or a read command, and take the appropriate actions.

Example:


There are optimizations: you could limit the scope of the lock to the smallest possible by using the try{} blocks to copy data to member-local variables, as long as that doesn't create inconsistency. You should also read the docs about the ability to upgrade locks from read to write - it takes effort, so you need to know that a given thread would never have/need both locks.


Steve
Alvin Parker
Ranch Hand

Joined: Oct 01, 2013
Posts: 38
Excellent! Thank you. That's a huge distinction.

I'm going to implement what you've taught me.

Just for clarification, I'm still confused about the purpose of sychronized(object) - although I understand clearly your point that where you synchronize is imperative to getting expected results. So if I added the sychronized(controller) to the run method of the Runnable being executed by the Thread in question, would it not effectively give me the same features as the locking in the manner you've shown? edited to say (although with the difference that synchronized would presumably block everything every time it was used versus read locks which can run concurrently)
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4167
    
  21

A synchronized(controller) will only affect threads that synchronize on the same object. If a task doesn't do synchronized(controller) at all then it will be unaffected by the synchronized block. So if you put the synchronized(controller) only in the tasks that run the update, it would only block other tasks that also update the data, So tasks which read the data would be able to run at the same time as the update, and things could be inconsistent. To prevent that you would need to put the synchronized block on all tasks, reading or updating. But then you can only run one task at a time (whether it is updating or just reading) and your throughput would suffer. So you would need to be a lot more careful about the size of the block - make sure the reader tasks only synchronize when it needs to. And if you do that you need to be real careful about consistency over the course of the task. You should know that anyway to be efficient, but it is much more important if you use the synchronized(controller) pattern and only have one task running through those guarded sections at a time.

Whereas the ReadWriteLock allows all the reads to run concurrently, while making sure all writes block everything. The throughput should be higher as long as the writes are fairly infrequent. It is also a bit more forgiving if you over-synchronize since the lower efficiency would only be found when writes are concerned.
Alvin Parker
Ranch Hand

Joined: Oct 01, 2013
Posts: 38
That is very useful Steve. Thank you so very much. Locking writes is clearly far more elegant. From what you've taught me, using synchronized in this case would effectively make my multi-threaded program a single threaded async program. I'm glad I asked instead of barreling ahead with what I thought I understood.
Alvin Parker
Ranch Hand

Joined: Oct 01, 2013
Posts: 38
Just to update this thread, per Steve's comments regarding upgrading locks...

I have a single ReentrantReadWriteLock instantiated in my Runnable Factory. If a Runnable needs to block, I put this in place ( credit to the OP at this location :Relevant Posting Elsewhere)


 
It is sorta covered in the JavaRanch Style Guide.
 
subject: Clarifying Synchronize(object) (RESOLVED)
 
Similar Threads
Why the EOFException always thrown ?????
please answer this 128 questions for WLS. Urgently!
need some help with locking....
not sure which methods must be synchronized
NX:Client crashed cause deadlock in LockManager