Created
July 8, 2020 16:30
-
-
Save pratapaditya1997/2174e47d2ec96ab2db9c083b911b07c4 to your computer and use it in GitHub Desktop.
Lock and ReadWriteLock implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* in ReadWriteLock notifyAll() is called rather than notify() | |
* inside this lock many threads are waiting for read access and threads waiting for write access. if a thread is awakened by notify() was a read access thread, it would be put back to waiting because there are threads waiting for write access. | |
* however none of the threads awaiting write access are awakened, so nothing more happens. no threads gain neither read nor write access. | |
*/ | |
class ReadWriteLock { | |
private int readers = 0; | |
private int writers = 0; | |
private int writeRequests = 0; | |
public synchronized void lockRead() { | |
while(writers > 0 || writeRequests > 0) { | |
wait(); | |
} | |
readers++; | |
} | |
public synchronized void unlockRead() { | |
readers--; | |
notifyAll(); | |
} | |
public synchronized void lockWrite() { | |
writeRequests++; | |
while(readers > 0 || writers > 0) { | |
wait(); | |
} | |
writeRequests--; | |
writers++; | |
} | |
public synchronized void unlockWrite() { | |
writers--; | |
notifyAll(); | |
} | |
} | |
class ReadWriteLockReentrant { | |
private Map<Thread, Integer> readingThreads = new HashMap<Thread, Integer>(); | |
private int writerAccesses = 0; | |
private int writeRequests = 0; | |
private Thread writingThread = null; | |
public synchronized void lockRead() { | |
Thread callingThread = Thread.currentThread(); | |
while(!canGrantReadAccess(callingThread)) { | |
wait(); | |
} | |
readingThreads.put(callingThread, getAccessCount(callingThread) + 1); | |
} | |
public synchronized void unlockRead() { | |
Thread callingThread = Thread.currentThread(); | |
int accessCount = getAccessCount(callingThread); | |
if(accessCount == 1) { | |
readingThreads.remove(callingThread); | |
} else { | |
readingThreads.put(callingThread, accessCount - 1); | |
} | |
notifyAll(); | |
} | |
public synchronized void lockWrite() { | |
writeRequests++; | |
Thread callingThread = Thread.currentThread(); | |
while(!canGrantWriteAccess(callingThread)) { | |
wait(); | |
} | |
writeRequests--; | |
writerAccesses++; | |
writingThread = callingThread; | |
} | |
public synchronized void unlockWrite() { | |
writerAccesses--; | |
if(writerAccesses == 0) { | |
writingThread = null; | |
} | |
notifyAll(); | |
} | |
private boolean canGrantReadAccess(Thread callingThread) { | |
if(writers > 0) return false; | |
if(isReader(callingThread)) return true; | |
if(writeRequests > 0) return false; | |
return true; | |
} | |
private boolean canGrantWriteAccess(Thread callingThread) { | |
if(hasReaders()) return false; | |
if(writingThread == null) return true; | |
if(!isWriter(callingThread)) return false; | |
return true; | |
} | |
private int getAccessCount(Thread callingThread) { | |
Integer accessCount = readingThreads.get(callingThread); | |
if(accessCount == null) return 0; | |
return accessCount.intValue(); | |
} | |
private boolean hasReaders() { | |
return readingThreads.size() > 0; | |
} | |
private boolean isReader(Thread callingThread) { | |
return readingThreads.get(callingThread) != null; | |
} | |
private boolean isWriter(Thread callingThread) { | |
return writingThread == callingThread; | |
} | |
} | |
// to make the Lock class re-entrant we need to store current thread too | |
class Lock { | |
boolean isLocked = false; | |
Thread lockedBy = null; | |
int lockedCount = 0; | |
public synchronized void lock() { | |
Thread callingThread = Thread.currentThread(); | |
while(isLocked && lockedBy != callingThread) { | |
wait(); | |
} | |
isLocked = true; | |
lockedCount++; | |
lockedBy = currentThread; | |
} | |
public synchronized void unlock() { | |
Thread currentThread = Thread.currentThread(); | |
if(this.lockedBy == currentThread) { | |
lockedCount--; | |
if(lockedCount == 0) { | |
isLocked = false; | |
notify(); | |
} | |
} | |
} | |
} | |
// we should always call unlock() method from the finally block so that other threads can block it if there is some exception | |
class Counter { | |
private Lock lock = new Lock(); | |
private int count = 0; | |
public int inc() { | |
lock.lock(); | |
try { | |
int newCount = ++count; | |
} finally { | |
lock.unlock(); | |
} | |
return newCount; | |
} | |
} | |
public class Locking { | |
public static void main(String[] args) { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment