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.
CodePudding user response:
You could achieve this by using the ReadWriteLock
interface implemented with a ReentrantReadWriteLock
instance. This class can represent your case of read and write by acquiring the corresponding lock when performing the getIds
and loadIds
operations. In fact,
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.
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html
Basically, your loadIds
should acquire the write-lock before proceeding with its operations. If it succeeds, it immediately acquires the lock and carries on with its computation; otherwise it blocks the corresponding thread until the lock is obtained or an InterruptedException is thrown.
On the other hand, the getIds
method should acquire the read-lock instead. Where the current thread immediately obtains the lock if this is available; otherwise it 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;
}
}