implants the #75 reader writer lock
This commit is contained in:
@ -0,0 +1,82 @@
|
||||
package com.iluwatar.reader.writer.lock;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Reader writer lock is a synchronization primitive that solves one of the readers–writers
|
||||
* problems. An RW lock allows concurrent access for read-only operations, while write operations
|
||||
* require exclusive access.
|
||||
* <p>
|
||||
* Below example use two mutexes to demonstrate the concurrent access of mutilple readers and
|
||||
* writers.
|
||||
*
|
||||
*/
|
||||
public class App {
|
||||
|
||||
private static Random ran = new Random();
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
ExecutorService es = Executors.newFixedThreadPool(1000);
|
||||
ReaderWriterLock lock = new ReaderWriterLock();
|
||||
|
||||
AtomicInteger index = new AtomicInteger(0);
|
||||
IntStream.range(0, 100).forEach(i -> {
|
||||
Runnable task = null;
|
||||
if (ran.nextFloat() <= 0.6) {
|
||||
task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Lock writeLock = lock.writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
int cur = index.getAndIncrement();
|
||||
System.out.println("Writer " + cur + " begin");
|
||||
simulateReadOrWrite();
|
||||
System.out.println("Writer " + cur + " finish");
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
task = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Lock readLock = lock.readLock();
|
||||
readLock.lock();
|
||||
try {
|
||||
int cur = index.getAndIncrement();
|
||||
System.out.println("Reader " + cur + " begin");
|
||||
simulateReadOrWrite();
|
||||
System.out.println("Reader " + cur + " finish");
|
||||
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
es.submit(task);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static void simulateReadOrWrite() {
|
||||
try {
|
||||
Thread.sleep((long) (ran.nextFloat() * 10));
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.iluwatar.reader.writer.lock;
|
||||
|
||||
/**
|
||||
* Lock interface
|
||||
*/
|
||||
public interface Lock {
|
||||
|
||||
/**
|
||||
* Try to lock, it will wait until get the lock
|
||||
*/
|
||||
public void lock();
|
||||
|
||||
/**
|
||||
* Release lock
|
||||
*/
|
||||
public void unlock();
|
||||
}
|
||||
|
@ -0,0 +1,147 @@
|
||||
package com.iluwatar.reader.writer.lock;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class responsible for control the access for reader or writer
|
||||
*/
|
||||
public class ReaderWriterLock {
|
||||
|
||||
/**
|
||||
* Mutex for reader
|
||||
*/
|
||||
private Object r = new Object();
|
||||
|
||||
/**
|
||||
* Global mutex for reader or writer, use to save the holding object
|
||||
*/
|
||||
private Set<Object> g = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Current reader count
|
||||
*/
|
||||
private int readerCount = 0;
|
||||
|
||||
private ReaderLock readLock = new ReaderLock();
|
||||
private WriterLock writeLock = new WriterLock();
|
||||
|
||||
|
||||
public Lock readLock() {
|
||||
return readLock;
|
||||
}
|
||||
|
||||
|
||||
public Lock writeLock() {
|
||||
return writeLock;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reader Lock, can be access for more than one reader concurrently if no writer get the lock
|
||||
*/
|
||||
private class ReaderLock implements Lock {
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
|
||||
synchronized (r) {
|
||||
|
||||
readerCount++;
|
||||
if (readerCount == 1) {
|
||||
|
||||
synchronized (g) {
|
||||
|
||||
while (true) {
|
||||
if (isLockFree() || isReaderOwnThisLock()) {
|
||||
g.add(this);
|
||||
break;
|
||||
} else {
|
||||
waitUninterruptely(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
|
||||
synchronized (r) {
|
||||
readerCount--;
|
||||
if (readerCount == 0) {
|
||||
synchronized (g) {
|
||||
g.remove(this);
|
||||
g.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writer Lock, can only be accessed by one writer concurrently
|
||||
*/
|
||||
private class WriterLock implements Lock {
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
|
||||
synchronized (g) {
|
||||
|
||||
while (true) {
|
||||
|
||||
if (isLockFree()) {
|
||||
g.add(this);
|
||||
break;
|
||||
} else if (isWriterOwnThisLock()) {
|
||||
waitUninterruptely(g);
|
||||
} else if (isReaderOwnThisLock()) {
|
||||
waitUninterruptely(g);
|
||||
} else {
|
||||
throw new RuntimeException("it should never reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
|
||||
synchronized (g) {
|
||||
g.remove(this);
|
||||
g.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWriterOwnThisLock() {
|
||||
return g.contains(writeLock);
|
||||
}
|
||||
|
||||
private boolean isReaderOwnThisLock() {
|
||||
return g.contains(readLock);
|
||||
}
|
||||
|
||||
private boolean isLockFree() {
|
||||
return g.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void waitUninterruptely(Object o) {
|
||||
try {
|
||||
o.wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.iluwatar.reader.writer.lock;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.iluwatar.reader.writer.lock.App;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user