0

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.

1
  • @Dan surely I will accept your answer, it is very clear. I have added one comment please check. Commented Apr 22, 2022 at 9:15

1 Answer 1

2

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;
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

thanks for the clear answer. Surely I will accept your answer. But I have few clarifications on the code. I have written getters for lock, readLock and writeLock in the contextManager class. And I made below changes in ConfigManager class ctxManager.writeLock() -- ctxManager.getLock().writeLock(); Whether I need to release writeLock() in finally block? added below code in fianlly block. ctxManager.unlock(); --> ctxManager.getWriteLock().unlock();
I would be careful with using ReadWriteLock without proper performance measurements. If the writes are infrequent, it is probably better to use StampedLock.
@MuralikrishnaKonduru I haven't understood properly your question, but if you're asking me why you need to place your unlock within a finally-block, it is only to ensure that the lock will be release no matter what. Say an exception is raised while you're performing your operation and the read or write lock have been acquired. Nobody else would be able to access those resources anymore because no one will ever release those locks.
@alchemist true, write performances might be a problem, but this is intrinsic in its application model since what he/she wants is that no other thread should access the array in write or read mode if any other is already accessing it in write mode. I guess enabling the "fair mode" could decrease the overall throughput if writings are quite frequent, in that case he/she might help it by invoking the empty constructor (or by passing false to the current one). Nonetheless, yours was a correct observation, I agree with you, but I guess this is also part of the application constraints.
@Dan In ConfigManager.java there is ctxManager.unlock(); I guess I have to release both readLock and writeLock, because once write is done I have to allow cache reading. so It should be ctxManager.getWriteLock().unlock(); and ctxManager.getReadLock().unlock();
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.