• Post Reply Bookmark Topic Watch Topic
  • New Topic

Execution order of threads synced on a common object

 
Tushar Madhukar
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,

My app has a pool of objects, where each object can possibly be accessed simultaneously by many servlet threads. I also have an admin thread, that removes the object from the pool, if it has been idle for too long.

Now, the admin thread can only clear the object, if no servlet thread is accessing it or is waiting to acquire a lock on it. That means, I need some way to guarantee that the admin thread should be the last one to get a lock on the object. How to do this?

A wait/notify paradigm doesn't guarantee an execution order, which I am looking for. Is there someway I can access the wait list associated with the object? That way I would know if there are any threads waiting on it apart from the admin thread.

Thanks
 
Henry Wong
author
Sheriff
Posts: 22529
109
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A wait/notify paradigm doesn't guarantee an execution order, which I am looking for.


With Java 5.0, you still can't guarantee (absolute) execution order, but you can, under contention, get the condition variable mechanism to be "fair". This will give you some execution order.

Basically, if you replace the synchronization with the ReentrantLock class, and using the newCondition() method to get a Condition object for wait/notify (actually await/signal), you can get ordering, if you use the "fairness" flag.

Henry
 
Edward Harned
Ranch Hand
Posts: 291
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Need more information here:

What is a " pool of objects"?

What is a "servlet thread"?

What is an "admin thread"?

What type of lock are you using to access the objects?
 
Tushar Madhukar
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This is in context of a web application.

A pool/cache is just a collection of application objects, which contain information retrieved from database.

Several clients can simultaneously access one or more data in the cache. Hence, different threads (executing a servlet's service()) have synchronized access to these objects i.e. they lock the object before accessing/updating it and release it subsequently.

A separately spawned thread manages the pool e.g. keeps pool size within limits, removes unused pool objects etc. This the "admin" thread.
 
Nitesh Kant
Bartender
Posts: 1638
IntelliJ IDE Java MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Tushar,
One question, the pool of objects that you have is a simple hashmap that the threads access directly? Or there is wrapper pool object that has interface to retrieve/return objects from the pool.
If you have a wrapper to access the pool, then you can associate a meta data with each object having a counter(AtomicInteger) that how many threads are accessing the object currently. (Access is defined as a get call not followed by a return call to the pool)
The admin thread can wake up after a scheduled time and clean up the idle objects(zero threads accessing that object.)
Since, admin thread is a kind of clean up thread, i believe it would not bother you if for a small time an object is unreferenced, exceeds idle time and not cleared. What i mean by this is the following:

Instance t1:
Thread1 retrieves pooled object1

Intance t2:
Admin thread runs. Does not clear object1

Instance t3:
Thread 1 returns pooled object1

Instance t4:
Admin thread clears the object.

Time between t4 and t3 is the idle period for the object. It may or may not be more than the configured period. If it is less then it will be cleared in the next run of admin thread.
Generally, clean ups are not of that high accuracy and can live with the above limitation.
Having proposed the above, this solution assumes a well behaved client i.e. one who takes an object should return it. If this is not the case, then you have to use a timeout period.

If you are exposing the hashmap of object pools directly, its high time you wrap it up with an object.
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I don't think an AtomicInteger will offer enough control here - you need to be able to run a clear() method only if the number of threads waiting is zero. The problem is that it's possible another thread starts waiting after you've checked that n = 0, before the clear() method is called. You need synchronization or java.util.concurrent locking to prevent these sorts of gaps.

One option for maximum control over which threads get notified and in what order is to use the Specific Notification Pattern. Basically this means you keep a set of monitors, one for each thread. Calling notify() on a given monitor will wake only the one thread that's associated with the monitor. So then it's up to you to decide which threads you want to notify about a given event.

Another option which may be a better fit for this specific problem is to wrap each cached data object in a wrapper class which keeps track of how many threads are waiting to do something with that object.

Here the usedAtLeastOnce flag is intended to prevent performLast() from taking effect before at least one other action has been performed on the object. At least for a cached object this makes sense - there must have been some reason to create the object in the first place, and we don't want the object accidentally cleaned up before it's been used. After that though, it could be cleaned up any time the number of clients (threads waiting to perform an action) drops down to 0.

Here's a demo of it in use:

which results in

Note that although it was ready to print the result right away, that thread was forced to wait until the others had completed before it run.

The main() method above may look a bit cumbersome for the client, but remember that at least half of the code you see here is setting up separate threads for everything. In practice the multiple threads were already part of the infrastructure. And the Action interface may be a bit unusual-looking (why force the user to create an anonymous class instance?) but it allows us to control the circumstances under which the method is finally called. The alternative was for the client to do something like this:

and hope that the client didn't do anything else with the StringBuilder after they called finished(). Nah, too many things can go wrong there.
[ May 11, 2007: Message edited by: Jim Yingst ]
 
Nitesh Kant
Bartender
Posts: 1638
IntelliJ IDE Java MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Jim,
No doubt, its a great solution to the problem at hand.
However, i feel that if i need a simple object pool, its a little overhead. The following reasons in support for my thinking:

1) Every object cached results in one more object created.(Guarded object)
2) Every cached object object used creates one more object. (Action object)

So, in a nutshell this would result in 2 extra objects created per cached object.
However, the positives:
1) Admin thread does not run when it has nothing to clean.
2) Cached object is never exposed directly to the client.

Point 1 is a big advantage, but 2) depends really on the object cached.

hope that the client didn't do anything else with the StringBuilder after they called finished(). Nah, too many things can go wrong there.

Well, this depends on the cached object. IMHO, this will hurt only if the cached object holds a live connection with some resource and cleaning an object means closing this connection.
However, if it is a cache of simple data objects(that it was according to the question), it doesnt really hurt, even if the client uses the object after finished()

I don't think an AtomicInteger will offer enough control here

I agree. It was a bad choice. As you said, synchronization or locks is the best choice.
 
Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This would sure be easier without the requirement to know if there are objects waiting for a lock. Let's see if we can ignore it. Put a field on each object in the pool for last access timestamp. The admin thread has another field - max time to live which has to be quite a bit bigger than the time we expect any other thread to hold access to the objects.

If anybody is using an object now the last access will be relatively recent, not long enough to remove from pool. If anybody else is waiting on the object, the current user will finish and the next user will reset last access time, so on the next admin sweep the last access will be relatively recent again.

Is that even needed? What happens if we remove an object from the pool while several other threads are blocked on synchronized clauses? The other threads all have references to the object so it cannot be gc until they all finish and their references go out of scope.
 
Nitesh Kant
Bartender
Posts: 1638
IntelliJ IDE Java MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Is that even needed? What happens if we remove an object from the pool while several other threads are blocked on synchronized clauses? The other threads all have references to the object so it cannot be gc until they all finish and their references go out of scope.

The only point i can think of is, if the creation of the object, i.e. in this case reading from the db, takes enough resource and time(precisely the reason why someone uses object pools ), it would not make sense to remove it from the pool when someone is using it. So, i would say, that it is nice if the pool can determine whether an object is *in use* or not and then only remove.
This would sure be easier without the requirement to know if there are objects waiting for a lock. Let's see if we can ignore it. Put a field on each object in the pool for last access timestamp. The admin thread has another field - max time to live which has to be quite a bit bigger than the time we expect any other thread to hold access to the objects.

James, IMHO, this approach is quite similar to having a client count for every object, the only change being that only *get* is recorded and not *finish*. The assumption being, a client does not do a processing long enough than the max idle time. Most of the practical cases it will be a valid assumption, but is definetly a grey area.
However, it all boils down to the point as to what we are pooling. If the cleaning of the object in the pool affects the clients then what Jim suggested is by far the best approach. But, if not, then probably it makes sense to take a little less stringent approach!
Worth mentioning again, i really liked Jim's approach for one reason i.e. Admin thread works only when required i.e. if there is something to be cleaned. In the other approaches, admin thread sleeps for sometime and then finds out whether something needs to be cleaned.
 
Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thinking some more, it seems the real requirement is to remove something that hasn't been used for a while, and the timestamp update on "get" is probably pretty good.

There are many choices on the admin sweep. You might do it on its own thread every n seconds. I made one that did a sweep only when somebody accessed the cache (on the accessor's thread because I wasn't able to run my own for some reason) and a sweep interval time had gone by. You could sweep depending on cache size, available memory or any other logic you can come up with. On top of all that, I'm sure I'd have a manual sweep or clear command from a dashboard, too.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!