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
"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
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With