javaarraysmultithreadingcachingthread-synchronization

In Java how to synchronize cache read and write operations


I am working on implementing a simple cache using ArrayList in my application.

I would like to synchronize cache update operations, while updating the cache I should not allow to perform read operations. So once cache update is completed, then only cache should allow to read.

ContextManager.java

public class ContextManager{
    private List<String> trashCanIds;
    public List<String> getIds() {
        return ids;
    }

    public void setIds(List<String> ids) {
        this.ids = ids;
    }
}

ConfigManager.java

public class ConfigManager{
    ContextManager ctxManager = new ContextManager();
    public synchronized List<String> loadIds() throws Exception {
        Utils utils = new Utils();
        List<String> listIds = null;
        String[] ids = utils.fetchIds();    
        if(Objects.nonNull(ids) && ids.length > 0) {
            listIds = new ArrayList<>(Arrays.asList(ids[0].split(",")));
        }
        ctxManager.setIds(idsList);
        return idsList;
    }
}

DeleteManager.java

public class DeleteManager {
    ConfigManager configManager = new ConfigManager();
    configManager.loadIds();
}

TestManager.java

public class TestManager {
    ContextManager contextManager = new ContextManager();
    contextManager.getIds();
}

In this code I have synchronized the loadIds() method.

Need help, how to prevent reading getIds() while loadIds() in progress.


Solution

  • You could achieve your goal by using the ReadWriteLock interface. Specifically, the ReentrantReadWriteLock implementation. This class can handle your read and write cases by acquiring the corresponding lock when performing the getIds and loadIds operations.

    A ReadWriteLock maintains a pair of associated locks, one for read-only operations and one for writing. The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive.

    Basically, loadIds should acquire the write-lock before proceeding with its operations. If it succeeds, it immediately acquires the lock, and then carries on with its computation. If not, the method blocks the corresponding thread until the lock is obtained or an InterruptedException is thrown.

    Conversely, the getIds method should acquire the read-lock. In this scenario, if the lock is available, the current thread obtains the lock and moves on. Otherwise, the method blocks the corresponding thread until the lock is obtained or an InterruptedException is thrown.

    ContextManager.java

    public class ContextManager{
        private List<String> trashCanIds;
        private ReadWriteLock lock;
        private Lock readLock;
        private Lock writeLock;
    
        public ContextManager(){
            lock = new ReentrantReadWriteLock(true);
            readLock = lock.readLock();
            writeLock = lock.writeLock();    
        }
    
        public List<String> getIds() {
            readLock.lock();
            try {
                List<String> tempTrashCanIds = new ArrayList(trashCanIds);
            } finally {
                readLock.unlock();
            }
            return tempTrashCanIds;
        }
    
        public void setIds(List<String> ids) {
            this.ids = ids;
        }
    
        public void readLock(){
            this.readLock.lock();
        }
    
        public void readUnlock(){
            this.readLock.unlock();
        }
    
        public void writeLock(){
            this.writeLock.lock();
        }
    
        public void writeUnlock(){
            this.writeLock.unlock();
        }
    }
    

    ConfigManager.java

    public class ConfigManager{
        ContextManager ctxManager = new ContextManager();
        public List<String> loadIds() throws Exception {
            Utils utils = new Utils();
            List<String> listIds = null;
            String[] ids = utils.fetchIds();    
            if(Objects.nonNull(ids) && ids.length > 0) {
                listIds = new ArrayList<>(Arrays.asList(ids[0].split(",")));
            }
    
            ctxManager.writeLock();
            try {
                ctxManager.setIds(idsList);
            } finally {
                ctxManager.writeUnlock();
            }
            return idsList;
        }
    }