implants the #75 reader writer lock

This commit is contained in:
hoswey
2015-12-26 14:17:24 +08:00
parent a0151826ad
commit 3731d26f6d
9 changed files with 409 additions and 0 deletions

View File

@ -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 readerswriters
* 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();
}
}
}

View File

@ -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();
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}