views:

65

answers:

5

I want to cache a object in memory. Regenerating the object when the cache expires is fairly expensive, so I want to do the following:

When the cache is "about" to expire, I want to fire off a asychronous thread that will go and rebuild the object and then reset the cache.

One thing I am worry about is multiple threads firing to fetch the object to cache, I only want a single thread doing this, realizing many people will be hitting the website.

This might not be the best use case to do this, but I want to know how to do this sort of thing.

A: 

you should be able to use lock(this){} on a section of code to ensure that only one thread can access it at a time.

alternatively, you can cache a boolean value and set it to true when you fire your async thread, checking it before firing said thread and if its false, abort the intended operation

Lerxst
Locking on this will only guarantee synchronization on a single instance of a thread, assuming this references Thread. So if the thread is instantiated/started from a web request service method it is of no help.
Raymond
true, but what about the second portion of my answer?
Lerxst
+1  A: 

I'd personally use a scheduler of some sort to trigger the re-creation of the object and the cache renewal and set the object to never be invalidated automatically in the cache.

Loki
A: 

You could start a thread during initialization of your web application and let him wait for expiration of your expensive object, go sleep again and wait for next expiration, ...

tangens
+3  A: 

You're looking for java.util.concurrent.Executors.newSingleThreadScheduledExecutor():

Creates a single-threaded executor that can schedule commands to run after a given delay, or to execute periodically. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.) Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time. Unlike the otherwise equivalent newScheduledThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads.

Nathan Hughes
+1  A: 

You should use a ScheduledExecutorService. If I were to write this, I would do it in a similar way to:

    Object cachedObject = null;
    ReadWriteLock lock = new ReentrantReadWriteLock();

    ScheduledExecutorService cacheService = Executors.newScheduledThreadPool(1);
    cacheService.scheduleAtFixedRate(new Runnable(){
        public void run(){
            lock.writeLock().lock();
            try{
               cachedObjcet = //built object
            }finally{
                lock.writeLock().unlock();
            }
        }
    }, 0, N, X);
    //where 
      // N is the amount of time until expiriation 
      // X is the time units that N is represented by
    public Object getCachedObject(){
        lock.readLock().lock();
        try{
            return cachedObject;
        }finally{
            lock.readLock().unlock();
        }
    }
John V.