Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java cached object return old value

I have Cached List, my code looks like this

public class MyList {
private final List<String> cache = new ArrayList<String>();

private List<String> loadMyList() {
    // HEAVY OPERATION TO LOAD DATA
}

public List<String> list() {
    synchronized (cache) {
        if( cache.size() == 0 ) {
            cache.addAll(loadMyList());
        }
        return Collections.unmodifiableList(cache);
    }
}

public void invalidateCache() {
    synchronized (cache) {
        cache.clear();
    }
}
}

Because list load is very heavy I got a request that if list load is currently in progress i return "old" cached data...

Is that possible, and can someone give me pointers on how to proceed from here

EDIT : Adam Horvath And bayou.io sugested something like this

public class MyList 
{
private final List<String> cache = new ArrayList<String>();
private final List<String> oldCache = new ArrayList<String>();
private volatile boolean loadInProgress = false;

private List<String> loadMyList()
{
    // HEAVY OPERATION TO LOAD DATA
}

public List<String> list()
{
    synchronized (cache)
    {
        if( loadInProgress )
            return Collections.unmodifiableList( oldCache );
        else
            return Collections.unmodifiableList(cache);
    }
}

public void invalidateCache()
{
    synchronized (cache)
    {
        // copy to old cache
        oldCache = new ArrayList<String>( cache );
        // set flag that load is in progress
        loadInProgress = true;
        // clear cache
        cache.clear();

        // initialize load in new thread
        Thread t = new Thread(new Runnable()
        {
            public void run()
            {
                cache.addAll( loadMyList() );
                // set flag that load is finished
                loadInProgress = false;
            }
       });  
       t.start();


    }

   }
}

Will this edited code have any issues?? Since I am not experienced in multithreading and/or cashing optimisation i would appreciate any and all performance suggestion

like image 831
John Avatar asked Jul 09 '15 13:07

John


1 Answers

"Because list load is very heavy I got a request that if list load is currently in progress i return "old" cached data..."

This will not happen because of your "synchronized (cache)" block. You need a volatile boolean flag (mutex) to tell you a List is being generated. When a Thread tries to get list() and mutex is true, then it will receive the Cached one. Set it false when loadMyList() is completed.

So, remove the synchronized block and start loading your list in a seperate Thread.

public class MyList {
    private List<String> cache = new ArrayList<String>();
    private volatile boolean loadInProgress = false;

    private List<String> loadMyList() {
        // HEAVY OPERATION TO LOAD DATA
    }

    public List<String> list() {
        // Whatever is in cache, you can always return it
        return Collections.unmodifiableList(cache);
    }

    /**
     * Starts the loader-thread and then continues.
     */
    public void invalidateCache() {
        // Next two lines make sure only one Loader-thread can be started at the same time
        synchronized (cache) {
            if (!loadInProgress) {
                // initialize load in new thread
                Thread t = new Thread("Loader-thread") {
                    @Override
                    public void run() {
                        List<String> toAssign = loadMyList();
                        // You can simply assign instead of copying
                        cache = toAssign;
                        // cache now "points to" refreshed list
                        loadInProgress = false;
                    }
                };
                loadInProgress = true;
                t.start();
                // Now let's exit the synchronized block. Hopefully the Thread will start working soon
            } else {
                // A Thread is already working or about to start working, don't bother him
            }
        }
    }
}
like image 81
Adam Horvath Avatar answered Nov 14 '22 23:11

Adam Horvath