implants the #75 reader writer lock
This commit is contained in:
parent
a0151826ad
commit
3731d26f6d
1
pom.xml
1
pom.xml
@ -60,6 +60,7 @@
|
||||
<module>intercepting-filter</module>
|
||||
<module>producer-consumer</module>
|
||||
<module>poison-pill</module>
|
||||
<module>reader-writer-lock</module>
|
||||
<module>lazy-loading</module>
|
||||
<module>service-layer</module>
|
||||
<module>specification</module>
|
||||
|
BIN
reader-writer-lock/etc/reader-writer-lock.png
Normal file
BIN
reader-writer-lock/etc/reader-writer-lock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
94
reader-writer-lock/etc/reader-writer-lock.ucls
Normal file
94
reader-writer-lock/etc/reader-writer-lock.ucls
Normal file
@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
|
||||
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
|
||||
<class id="1" language="java" name="com.iluwatar.reader.writer.lock.ReaderWriterLock.ReaderLock"
|
||||
project="reader-writer-lock"
|
||||
file="/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="305" y="511"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="2" language="java" name="com.iluwatar.reader.writer.lock.ReaderWriterLock" project="reader-writer-lock"
|
||||
file="/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="394" y="270"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="3" language="java" name="com.iluwatar.reader.writer.lock.App" project="reader-writer-lock"
|
||||
file="/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="671" y="274"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<interface id="4" language="java" name="com.iluwatar.reader.writer.lock.Lock" project="reader-writer-lock"
|
||||
file="/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Lock.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="101" width="148" x="322" y="597"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</interface>
|
||||
<class id="5" language="java" name="com.iluwatar.reader.writer.lock.ReaderWriterLock.WriterLock"
|
||||
project="reader-writer-lock"
|
||||
file="/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java" binary="false"
|
||||
corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="488" y="509"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<nesting id="6">
|
||||
<end type="SOURCE" refId="2"/>
|
||||
<end type="TARGET" refId="5"/>
|
||||
</nesting>
|
||||
<realization id="7">
|
||||
<end type="SOURCE" refId="5"/>
|
||||
<end type="TARGET" refId="4"/>
|
||||
</realization>
|
||||
<realization id="8">
|
||||
<end type="SOURCE" refId="1"/>
|
||||
<end type="TARGET" refId="4"/>
|
||||
</realization>
|
||||
<association id="9">
|
||||
<end type="SOURCE" refId="2" navigable="false">
|
||||
<attribute id="10" name="writeLock"/>
|
||||
<multiplicity id="11" minimum="0" maximum="1"/>
|
||||
</end>
|
||||
<end type="TARGET" refId="5" navigable="true"/>
|
||||
<display labels="true" multiplicity="true"/>
|
||||
</association>
|
||||
<association id="12">
|
||||
<end type="SOURCE" refId="2" navigable="false">
|
||||
<attribute id="13" name="readLock"/>
|
||||
<multiplicity id="14" minimum="0" maximum="1"/>
|
||||
</end>
|
||||
<end type="TARGET" refId="1" navigable="true"/>
|
||||
<display labels="true" multiplicity="true"/>
|
||||
</association>
|
||||
<nesting id="15">
|
||||
<end type="SOURCE" refId="2"/>
|
||||
<end type="TARGET" refId="1"/>
|
||||
</nesting>
|
||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</classifier-display>
|
||||
<association-display labels="true" multiplicity="true"/>
|
||||
</class-diagram>
|
29
reader-writer-lock/index.md
Normal file
29
reader-writer-lock/index.md
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Producer Consumer
|
||||
folder: reader writer lock
|
||||
permalink: /patterns/reader-writer-lock/
|
||||
categories: Concurrent
|
||||
tags:
|
||||
- Java
|
||||
---
|
||||
|
||||
**Intent:**
|
||||
|
||||
Suppose we have a shared memory area with the basic constraints detailed above. It is possible to protect the shared data behind a mutual exclusion mutex, in which case no two threads can access the data at the same time. However, this solution is suboptimal, because it is possible that a reader R1 might have the lock, and then another reader R2 requests access. It would be foolish for R2 to wait until R1 was done before starting its own read operation; instead, R2 should start right away. This is the motivation for the Reader Writer Lock pattern.
|
||||
|
||||

|
||||
|
||||
**Applicability:**
|
||||
|
||||
Application need to increase the performance of resource synchronize for multiple thread, in particularly there are mixed read/write operations.
|
||||
|
||||
**Real world examples:**
|
||||
|
||||
* [Java Reader Writer Lock](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html)
|
||||
|
||||
**Credits**
|
||||
|
||||
* [Readers–writer lock](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock)
|
||||
|
||||
* [Readers–writers_problem](https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem)
|
18
reader-writer-lock/pom.xml
Normal file
18
reader-writer-lock/pom.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.9.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>reader-writer-lock</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user