diff --git a/monitor-object/README.md b/monitor-object/README.md
new file mode 100644
index 000000000000..45abaa26b2d0
--- /dev/null
+++ b/monitor-object/README.md
@@ -0,0 +1,27 @@
+---
+layout: pattern
+title: Monitor Object
+folder: monitor-object
+permalink: /patterns/monitor-object/
+categories: Concurrency
+tags:
+ - Java
+ - Difficulty-Intermediate
+---
+
+## Intent
+In 1974, Tony Hoare proposed the concept of monitors for designing and reasoning about objects that are shared between multiple threads. The key property of these "Hoare-style" monitors is that threads can wait until some specific assertion about the monitor's state is true and be guaranteed that it is still true after the thread has been awakened. The purpose of the Monitor Object is to provide an implementation of Hoare-style monitors for thread communication in a Java-based monitor package that automates assertion checking during execution. This approach reduces redundant coding and automates assertions checking during execution.
+
+
+
+## Applicability
+Use the Monitor Object Pattern for thread signaling (over Java's wait() and notify() approach) in the following situations:
+
+* When you need Defensive programming in multithreaded code - The monitor package provides support for defensive programming through the invariant() method and the assertion objects associated with each condition object. Java's notify() and wait() provide no assertion checking
+* When you need objects to wait on multiple wait queues - The monitor package provides condition objects, each providing its own wait queue. Threads waiting for different assertions to become true wait on different queues. Using wait(), there is only one wait queue per object.
+* When you need seamless passing of occupancy - In the monitor package, control is passed seamlessly from the signaling thread to an awaiting thread. You can be sure that, after returning from an await(), the assertion the thread has waited for is true. In contrast, the notify() and notifyAll() methods simply move a waiting thread back to the entry queue for the monitor.
+
+## Credits
+
+* [Theodore S. Norvell - Monitor Object](https://www.javaworld.com/article/2077769/core-java/better-monitors-for-java.html)
+* [Monitor (syncronization)](https://en.wikipedia.org/wiki/Monitor_(synchronization))
diff --git a/monitor-object/etc/monitor-object.png b/monitor-object/etc/monitor-object.png
new file mode 100644
index 000000000000..a6d736894e24
Binary files /dev/null and b/monitor-object/etc/monitor-object.png differ
diff --git a/monitor-object/etc/monitor-object.ucls b/monitor-object/etc/monitor-object.ucls
new file mode 100644
index 000000000000..fd7c113f5f17
--- /dev/null
+++ b/monitor-object/etc/monitor-object.ucls
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/monitor-object/pom.xml b/monitor-object/pom.xml
new file mode 100644
index 000000000000..d5da9ff5440f
--- /dev/null
+++ b/monitor-object/pom.xml
@@ -0,0 +1,48 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.20.0-SNAPSHOT
+
+ monitor-object
+ monitor-object
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/AbstractMonitor.java b/monitor-object/src/main/java/com/iluwatar/monitor/AbstractMonitor.java
new file mode 100644
index 000000000000..922ec7e3ced5
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/AbstractMonitor.java
@@ -0,0 +1,236 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+import java.util.ArrayList;
+
+/**
+ * A class for Monitors. Monitors provide coordination of concurrent threads.
+ * Each Monitor protects some resource, usually data. At each point in time a
+ * monitor object is occupied by at most one thread.
+ */
+public abstract class AbstractMonitor {
+ final Semaphore entrance = new Semaphore(1);
+ volatile Thread occupant = null;
+ private final ArrayList listOfListeners = new ArrayList<>();
+ private final String name;
+
+ public String getName() {
+ return name;
+ }
+
+ protected AbstractMonitor() {
+ this(null);
+ }
+
+ protected AbstractMonitor(String name) {
+ this.name = name;
+ }
+
+ /**
+ * The invariant. The default implementation always returns true. This method
+ * should be overridden if at all possible with the strongest economically
+ * evaluable invariant.
+ */
+ protected boolean invariant() {
+ return true;
+ }
+
+ /**
+ * Enter the monitor. Any thread calling this method is delayed until the
+ * monitor is unoccupied. Upon returning from this method, the monitor is
+ * considered occupied. A thread must not attempt to enter a Monitor it is
+ * already in.
+ */
+ protected void enter() {
+ notifyCallEnter();
+ entrance.acquire();
+ // The following assertion should never trip!
+ Assertion.check(occupant == null, "2 threads in one monitor");
+ occupant = Thread.currentThread();
+ notifyReturnFromEnter();
+ Assertion.check(invariant(), "Invariant of monitor " + getName());
+ }
+
+ /**
+ * Leave the monitor. After returning from this method, the thread no longer
+ * occupies the monitor. Only a thread that is in the monitor may leave it.
+ *
+ * @throws AssertionError
+ * if the thread that leaves is not the occupant.
+ */
+ protected void leave() {
+ notifyLeaveMonitor();
+ leaveWithoutATrace();
+ }
+
+ /**
+ * Leave the monitor. After returning from this method, the thread no longer
+ * occupies the monitor. Only a thread that is in the monitor may leave it.
+ *
+ * @throws AssertionError
+ * if the thread that leaves is not the occupant.
+ */
+ protected T leave(T result) {
+ leave();
+ return result;
+ }
+
+ void leaveWithoutATrace() {
+ Assertion.check(invariant(), "Invariant of monitor " + getName());
+ Assertion.check(occupant == Thread.currentThread(), "Thread is not occupant");
+ occupant = null;
+ entrance.release();
+ }
+
+ /**
+ * Run the runnable inside the monitor. Any thread calling this method will be
+ * delayed until the monitor is empty. The "run" method of its argument is then
+ * executed within the protection of the monitor. When the run method returns,
+ * if the thread still occupies the monitor, it leaves the monitor.
+ *
+ * @param runnable
+ * A Runnable object.
+ */
+ protected void doWithin(Runnable runnable) {
+ enter();
+ try {
+ runnable.run();
+ } finally {
+ if (occupant == Thread.currentThread()) {
+ leave();
+ }
+ }
+ }
+
+ /**
+ * Run the runnable inside the monitor. Any thread calling this method will be
+ * delayed until the monitor is empty. The "run" method of its argument is then
+ * executed within the protection of the monitor. When the run method returns,
+ * if the thread still occupies the monitor, it leaves the monitor. Thus the
+ * signalAndLeave method may be called within the run method.
+ *
+ * @param runnable
+ * A RunnableWithResult object.
+ * @return The value computed by the run method of the runnable.
+ */
+ protected T doWithin(RunnableWithResult runnable) {
+ enter();
+ try {
+ return runnable.run();
+ } finally {
+ if (occupant == Thread.currentThread()) {
+ leave();
+ }
+ }
+ }
+
+ /**
+ * Create a condition queue associated with a checked Assertion. The Assertion
+ * will be checked prior to an signal of the condition.
+ */
+ protected Condition makeCondition(Assertion prop) {
+ return makeCondition(null, prop);
+ }
+
+ /**
+ * Create a condition queue with no associated checked Assertion.
+ */
+ protected Condition makeCondition() {
+ return makeCondition(null, TrueAssertion.SINGLETON);
+ }
+
+ /**
+ * Create a condition queue associated with a checked Assertion. The Assertion
+ * will be checked prior to an signal of the condition.
+ */
+ protected Condition makeCondition(String name, Assertion prop) {
+ return new Condition(name, this, prop);
+ }
+
+ /**
+ * Create a condition queue with no associated checked Assertion.
+ */
+ protected Condition makeCondition(String name) {
+ return makeCondition(name, TrueAssertion.SINGLETON);
+ }
+
+ /** Register a listener. */
+ public void addListener(MonitorListener newListener) {
+ listOfListeners.add(newListener);
+ }
+
+ private void notifyCallEnter() {
+ for (MonitorListener listener : listOfListeners) {
+ listener.callEnterMonitor(this);
+ }
+ }
+
+ private void notifyReturnFromEnter() {
+ for (MonitorListener listener : listOfListeners) {
+ listener.returnFromEnterMonitor(this);
+ }
+ }
+
+ private void notifyLeaveMonitor() {
+ for (MonitorListener listener : listOfListeners) {
+ listener.leaveMonitor(this);
+ }
+ }
+
+ void notifyCallAwait(Condition condition) {
+ for (MonitorListener listener : listOfListeners) {
+ listener.callAwait(condition, this);
+ }
+ }
+
+ void notifyReturnFromAwait(Condition condition) {
+ for (MonitorListener listener : listOfListeners) {
+ listener.returnFromAwait(condition, this);
+ }
+ }
+
+ void notifySignallerAwakesAwaitingThread(Condition condition) {
+ for (MonitorListener listener : listOfListeners) {
+ listener.signallerAwakesAwaitingThread(condition, this);
+ }
+ }
+
+ void notifySignallerLeavesTemporarily(Condition condition) {
+ for (MonitorListener listener : listOfListeners) {
+ listener.signallerLeavesTemporarily(condition, this);
+ }
+ }
+
+ void notifySignallerReenters(Condition condition) {
+ for (MonitorListener listener : listOfListeners) {
+ listener.signallerReenters(condition, this);
+ }
+ }
+
+ void notifySignallerLeavesMonitor(Condition condition) {
+ for (MonitorListener listener : listOfListeners) {
+ listener.signallerLeavesMonitor(condition, this);
+ }
+ }
+}
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/App.java b/monitor-object/src/main/java/com/iluwatar/monitor/App.java
new file mode 100644
index 000000000000..67ba1ad874a6
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/App.java
@@ -0,0 +1,48 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+/**
+ * Monitor Object Pattern for thread signaling.
+ */
+public class App {
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ int varX = 0;
+ int varY = 0;
+ Assertion.check(varX == varY);
+
+ varX = 0;
+ varY = 1;
+ Assertion.check(varX == varY);
+
+ varX = 0;
+ varY = 1;
+ Assertion.check(varX == varY, "Parameters Not Equal");
+ }
+}
\ No newline at end of file
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/Assertion.java b/monitor-object/src/main/java/com/iluwatar/monitor/Assertion.java
new file mode 100644
index 000000000000..c1107a50edd5
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/Assertion.java
@@ -0,0 +1,23 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
/**
* Assertions that may be checked from time to time.
*/
public abstract class Assertion {
private static final String DEFAULTMESSAGE = "Assertion Failure";
protected String message = DEFAULTMESSAGE;
/** This method says whether the assertion is true. */
public abstract boolean isTrue();
/** Throw an AssertionError if the assertion is not true. */
public void check() {
check(isTrue(), message);
}
/** Throw an AssertionError if the parameter is not true. */
public static void check(boolean b) {
check(b, DEFAULTMESSAGE);
}
/** Throw an AssertionError if the boolean parameter is not true. */
public static void check(boolean b, String message) {
if (!b) {
throw new AssertionError(message);
}
}
}
\ No newline at end of file
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/Condition.java b/monitor-object/src/main/java/com/iluwatar/monitor/Condition.java
new file mode 100644
index 000000000000..88d99c68ff1e
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/Condition.java
@@ -0,0 +1,23 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
/**
* A condition queue.
* Uses the signal and wait discipline (SW) or signal and leave (SL).
* Each Condition object is associated with a single {@link Assertion} object
* and a single AbstractMonitor
object. To construct a condition
* use the makeCondition
methods from
* {@link AbstractMonitor}
or {@link Monitor}
* Threads can wait for the assertion represented by the Assertion object to
* become true by calling method await()
. Threads can indicate that
* the assertion has become true by calling either method signal()
* (SW) or signalAndLeave()
(SL). All these methods check the
* assertion and the monitor's invariant as appropriate.
* Threads which wait on a Condition may supply a priority. In the absence of
* priority, waiting is fair -- in fact first-in last-out (FIFO).
* Each of the await()
, signal()
, and
* signalAndLeave()
methods have corresponding conditional
* versions, which first check the assertion before awaiting or signalling.
* These are: conditionalAwait()
, conditionalSignal()
,
* and conditionalSignalAndLeave()
.
* Conditions also support a {@link #count} accessor to determine the number of
* threads waiting on the condition.
* Condition objects are intended to be used only by the thread which occupies
* the monitor which created them.
*/
public class Condition {
private final AbstractMonitor homeMonitor;
private final Assertion assertion;
private final Semaphore queue;
private volatile int count;
private final String name;
Condition(String name, AbstractMonitor homeMonitor, Assertion assertion) {
this.name = name;
this.homeMonitor = homeMonitor;
this.assertion = assertion;
this.queue = new Semaphore(0);
this.count = 0;
}
public String getName() {
return name;
}
/**
* Just like await, but with a priority. Threads awaiting with a lesser priority
* value are re-admitted to the monitor in preference to threads awaiting with a
* greater priority value. When priority values are the same, the order is FIFO.
*
* @param priority
* Lower value means more urgent.
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* if the invariant is not true to start
* @throws AssertionError
* if the assertion is not true on return
* @see #await()
*/
public void await(int priority) {
homeMonitor.notifyCallAwait(this);
Assertion.check(homeMonitor.occupant == Thread.currentThread(), "Thread is not occupant");
count += 1;
Assertion.check(homeMonitor.invariant(), "Invariant of monitor " + homeMonitor.getName());
homeMonitor.occupant = null;
homeMonitor.entrance.release();
queue.acquire(priority);
count -= 1;
homeMonitor.occupant = Thread.currentThread();
// It's not clear that the following check is needed anymore,
// as there is now a check made on the signal.
assertion.check();
homeMonitor.notifyReturnFromAwait(this);
}
/**
* Wait until a condition is signalled. The thread waits outside the monitor
* until the condition is signalled.
* Precondition: Increasing the count by 1 must make the invariant true. This
* thread is in the monitor.
* Postcondition: The assertion associated with this condition queue. This
* thread is in the monitor.
* Note: threads are queued in a FIFO manner unless a priority is used;
* cond.await() is equivalent to cond.await( Integer.MAX_VALUE
* ).
*
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* if the invariant is not true to start
* @throws AssertionError
* if the assertion is not true on return
*/
public void await() {
await(Integer.MAX_VALUE);
}
/**
* Wait only if the condition is not already true.
*
* @throws AssertionError
* if neither the invariant nor the assertion associated with this
* object is true
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* if the assertion is not true on return
* @see #await()
*/
public void conditionalAwait() {
conditionalAwait(Integer.MAX_VALUE);
}
/**
* Just like conditionalAwait, but with a priority.
*
* @param priority
* Lower value means more urgent.
* @throws AssertionError
* if neither the invariant nor the assertion associated with this
* object is true
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* if the assertion is not true on return
* @see #conditionalAwait()
* @see #await( int priority )
*
*/
public void conditionalAwait(int priority) {
if (!assertion.isTrue()) {
await(priority);
}
}
/**
* Signal this condition if there is a waiting thread.
* Allows one thread that was waiting on the condition to reenter the monitor.
* Consequently the signalling thread waits outside. The signalling thread is
* allowed back into the monitor, once the monitor is again unoccupied. Threads
* which have signalled wait with a higher than normal priority and thus are
* allowed in ahead of other threads that are waiting to enter the monitor
* (e.g., those waiting in {@link AbstractMonitor#enter()}).
* If there is no waiting thread, then this is a no-op, but the invariant is
* still checked, as it is a postcondition.
* Preconditions:
*
* - If isEmpty(), the monitor's invariant must be true.
* - If not isEmpty(), then decreasing count() by 1 must make the proposition
* associated with this condition true.
* - This thread is in the monitor.
*
* Postcondition:
*
* - The monitor's invariant.
*
- This thread is in the monitor.
*
*
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* if there is a waiting thread and the assertion is false (after
* decreasing the count by 1).
* @throws AssertionError
* if invariant is false on return.
*
*/
public void signal() {
Assertion.check(homeMonitor.occupant == Thread.currentThread(), "Thread is not occupant");
if (count > 0) {
try {
count -= 1;
assertion.check();
} finally {
count += 1;
}
homeMonitor.notifySignallerLeavesTemporarily(this);
homeMonitor.notifySignallerAwakesAwaitingThread(this);
homeMonitor.occupant = null;
queue.release();
homeMonitor.entrance.acquire(0); // Priority 0 puts the signaller ahead of others.
homeMonitor.occupant = Thread.currentThread();
homeMonitor.notifySignallerReenters(this);
}
Assertion.check(homeMonitor.invariant(), "Invariant of monitor " + homeMonitor.getName());
}
/**
* Allows one thread which was waiting on the condition to reenter the monitor.
* This thread (the one calling signalAndLeave) leaves the monitor immediately.
* Preconditions:
*
* - If isEmpty(), the monitor's invariant must be true.
* - If not isEmpty(), then decreasing count() by 1 must make the proposition
* associated with this condition true.
* - This thread is in the monitor.
*
* Postcondition: This thread is not in the monitor.
*
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* if there is a waiting thread and the assertion is false (after
* decreasing the count by 1).
* @throws AssertionError
* if there is no waiting thread and the invariant is false.
* @see #signal()
*/
public void signalAndLeave() {
Assertion.check(homeMonitor.occupant == Thread.currentThread(), "Thread is not occupant");
if (count > 0) {
try {
count -= 1;
assertion.check();
} finally {
count += 1;
}
homeMonitor.notifySignallerAwakesAwaitingThread(this);
homeMonitor.occupant = null;
queue.release();
} else {
Assertion.check(homeMonitor.invariant(), "Invariant of monitor " + homeMonitor.getName());
homeMonitor.occupant = null;
homeMonitor.entrance.release();
}
homeMonitor.notifySignallerLeavesMonitor(this);
}
/**
* Signal if there is a waiting thread, then leave the monitor. Allows one
* thread which was waiting on the condition to reenter the monitor. This thread
* (the one calling signalAndLeave) leaves the monitor immediately.
* Preconditions:
*
* - If isEmpty(), the monitor's invariant must be true.
* - If not isEmpty(), then decreasing count() by 1 must make the proposition
* associated with this condition true.
* - This thread is in the monitor.
*
* Postcondition: This thread is not in the monitor.
*
* @param result
* A value to return.
* @return The value of the result parameter.
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* if there is a waiting thread and the assertion is false (after
* decreasing the count by 1).
* @throws AssertionError
* there is no waiting thread and the invariant is false.
*/
public T signalAndLeave(T result) {
signalAndLeave();
return result;
}
/**
* Signal this condition if its assertion is true and there is a waiting thread.
* More precisely the condition is only signalled if its assertion would be true
* after the count is decreased by 1 and there is a waiting tread.
* In such a case, the signalling thread waits outside. The signalling thread is
* allowed back into the monitor, once the monitor is again unoccupied. Threads
* which have signalled wait with a higher than normal priority and thus are
* allowed in ahead of other threads that are waiting to enter the monitor
* (e.g., those waiting in {@link AbstractMonitor#enter()}).
* If the there are no awaiting threads, or the condition's assertion would not
* be true after the count were decreased by one, this method is essentially a
* no-op, although the invariant is still checked in such a case.
* Preconditions:
*
* - If isEmpty(), the monitor's invariant must be true.
* - This thread is in the monitor.
*
* Postcondition:
*
* - The monitor's invariant.
*
- This thread is in the monitor.
*
*
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* if invariant is false on return.
* @see #signal()
*/
public void conditionalSignal() {
Assertion.check(homeMonitor.occupant == Thread.currentThread(), "Thread is not occupant");
if (count > 0) {
boolean wouldBeTrue;
count -= 1;
wouldBeTrue = assertion.isTrue();
count += 1;
if (wouldBeTrue) {
homeMonitor.notifySignallerAwakesAwaitingThread(this);
homeMonitor.notifySignallerLeavesTemporarily(this);
homeMonitor.occupant = null;
queue.release();
homeMonitor.entrance.acquire();
homeMonitor.occupant = Thread.currentThread();
homeMonitor.notifySignallerReenters(this);
}
}
Assertion.check(homeMonitor.invariant(), "Invariant of monitor " + homeMonitor.getName());
}
/**
* Signal this condition if its assertion is true and there is a waiting thread;
* leave regardless.
* More precisely the condition is only signalled if the assertion would be true
* after the count is decreased by 1 and there is a waiting thread.
* This thread (the one calling signalAndLeave) leaves the monitor immediately.
* Preconditions:
*
* - If isEmpty() or the assertion would be false after decreasing the count
* by 1, the monitor's invariant must be true.
* - This thread is in the monitor.
*
* Postcondition:
*
* - This thread is not in the monitor.
*
*
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* there is no waiting thread and the invariant is false.
* @throws AssertionError
* if there is a waiting thread and the assertion is false (after
* decreasing the count by 1) and the invariant is false.
* @see #signalAndLeave()
* @see #conditionalSignal()
*
*/
public void conditionalSignalAndLeave() {
Assertion.check(homeMonitor.occupant == Thread.currentThread(), "Thread is not occupant");
if (count > 0) {
boolean wouldBeTrue;
count -= 1;
wouldBeTrue = assertion.isTrue();
count += 1;
if (wouldBeTrue) {
homeMonitor.notifySignallerAwakesAwaitingThread(this);
homeMonitor.notifySignallerLeavesMonitor(this);
homeMonitor.occupant = null;
queue.release();
} else {
homeMonitor.notifySignallerLeavesMonitor(this);
homeMonitor.leaveWithoutATrace();
}
} else {
homeMonitor.notifySignallerLeavesMonitor(this);
homeMonitor.leaveWithoutATrace();
}
}
/**
* Signal this condition if its assertion is true and there is a waiting thread.
* Leave regardless. More precisely the condition is only signalled if the
* assertion would be true after the count is decreased by 1.
* This thread (the one calling signalAndLeave) leaves the monitor immediately.
* Preconditions:
*
* - If isEmpty() or the assertion would be false after decreasing the count
* by 1, the monitor's invariant must be true.
* - This thread is in the monitor.
*
* Postcondition:
*
* - This thread is not in the monitor.
*
*
* @param result
* A value to be returned.
* @return The value of the result parameter.
* @throws AssertionError
* if the current thread is not the occupant.
* @throws AssertionError
* there is no waiting thread and the invariant is false.
* @throws AssertionError
* if there is a waiting thread and the assertion is false (after
* decreasing the count by 1) and the invariant is false.
* @see #conditionalSignalAndLeave()
*
*/
public T conditionalSignalAndLeave(T result) {
conditionalSignalAndLeave();
return result;
}
/**
* Test if any thread is waiting on this condition.
*
* @return count() == 0 .
* @throws AssertionError
* if the current thread is not the occupant.
*/
public boolean isEmpty() {
Assertion.check(homeMonitor.occupant == Thread.currentThread(), "Thread is not occupant");
return count == 0;
}
/**
* How many threads are waiting on this condition.
*
* @return the number of Threads waiting on this condition.
* @throws AssertionError
* if the current thread is not the occupant.
*/
public int count() {
Assertion.check(homeMonitor.occupant == Thread.currentThread(), "Thread is not occupant");
return count;
}
}
\ No newline at end of file
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/Monitor.java b/monitor-object/src/main/java/com/iluwatar/monitor/Monitor.java
new file mode 100644
index 000000000000..1cd8fe59073a
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/Monitor.java
@@ -0,0 +1,54 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+/**
+ * A final class for Monitors.
+ */
+
+public final class Monitor extends AbstractMonitor {
+
+ private Assertion invariant;
+
+ public Monitor() {
+ this(TrueAssertion.SINGLETON);
+ }
+
+ public Monitor(Assertion invariant) {
+ this.invariant = invariant;
+ }
+
+ public Monitor(String name) {
+ this(name, TrueAssertion.SINGLETON);
+ }
+
+ public Monitor(String name, Assertion invariant) {
+ super(name);
+ this.invariant = invariant;
+ }
+
+ @Override
+ public boolean invariant() {
+ return invariant.isTrue();
+ }
+}
\ No newline at end of file
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/MonitorListener.java b/monitor-object/src/main/java/com/iluwatar/monitor/MonitorListener.java
new file mode 100644
index 000000000000..274796569552
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/MonitorListener.java
@@ -0,0 +1,50 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+/**
+ * Interface for listener to be registered and notified by the Monitor.
+ */
+public interface MonitorListener {
+
+ void nameThisThread(String name);
+
+ void callEnterMonitor(AbstractMonitor monitor);
+
+ void returnFromEnterMonitor(AbstractMonitor monitor);
+
+ void leaveMonitor(AbstractMonitor monitor);
+
+ void callAwait(Condition condition, AbstractMonitor monitor);
+
+ void returnFromAwait(Condition condition, AbstractMonitor monitor);
+
+ void signallerAwakesAwaitingThread(Condition condition, AbstractMonitor monitor);
+
+ void signallerLeavesTemporarily(Condition condition, AbstractMonitor monitor);
+
+ void signallerReenters(Condition condition, AbstractMonitor monitor);
+
+ void signallerLeavesMonitor(Condition condition, AbstractMonitor monitor);
+
+}
\ No newline at end of file
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/RunnableWithResult.java b/monitor-object/src/main/java/com/iluwatar/monitor/RunnableWithResult.java
new file mode 100644
index 000000000000..08115794803d
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/RunnableWithResult.java
@@ -0,0 +1,32 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+/**
+ * The runnable interface to be executed by a thread which returns a result.
+ *
+ * @param Parameter to specify the return type
+ */
+public interface RunnableWithResult {
+ T run();
+}
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/Semaphore.java b/monitor-object/src/main/java/com/iluwatar/monitor/Semaphore.java
new file mode 100644
index 000000000000..b17e4152ace4
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/Semaphore.java
@@ -0,0 +1,23 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
import java.util.LinkedList;
import java.util.ListIterator;
/**
* A FIFO semaphore.
*/
public class Semaphore {
// Each queue element is a a single use semaphore
class QueueElement {
final int priority;
volatile boolean enabled = false;
QueueElement(int priority) {
this.priority = priority;
}
synchronized void acquire() {
while (!enabled) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException("Unexpected interruption of "
+ "thread in monitor.Semaphore.acquire");
}
}
}
synchronized void release() {
enabled = true;
notify();
}
}
volatile int s1;
final LinkedList queue = new LinkedList();
// Invariant. All elements on the queue are in an unenabled state.
/** Initialize the semaphore to a value greater or equal to 0. */
public Semaphore(int initialvalue) {
Assertion.check(initialvalue >= 0);
this.s1 = initialvalue;
}
/**
* The P operation. If two threads are blocked at the same time, they will be
* served in FIFO order. sem.acquire() is equivalent to acquire(
* Integer.MAX_VALUE ).
*/
public void acquire() {
acquire(Integer.MAX_VALUE);
}
/**
* The P operation with a priority.
*
* @param priority
* The larger the integer, the less urgent the priority. If two
* thread are waiting with equal priority, they will complete acquire
* in FIFO order.
*/
public void acquire(int priority) {
QueueElement mine;
synchronized (this) {
if (s1 > 0) {
--s1;
return;
}
mine = new QueueElement(priority);
if (priority == Integer.MAX_VALUE) {
queue.add(mine);
} else {
ListIterator it = queue.listIterator(0);
int i = 0;
while (it.hasNext()) {
QueueElement elem = it.next();
if (elem.priority > priority) {
break;
}
++i;
}
queue.add(i, mine);
}
}
mine.acquire();
}
/** The V operation. */
public synchronized void release() {
QueueElement first = queue.poll();
if (first != null) {
first.release();
} else {
++s1;
}
}
}
\ No newline at end of file
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/TrueAssertion.java b/monitor-object/src/main/java/com/iluwatar/monitor/TrueAssertion.java
new file mode 100644
index 000000000000..00a1e2422a2b
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/TrueAssertion.java
@@ -0,0 +1,23 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
/**
* An assertion that is always true.
*/
public class TrueAssertion extends Assertion {
public boolean isTrue() {
return true;
}
public static final TrueAssertion SINGLETON = new TrueAssertion();
}
\ No newline at end of file
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/examples/Queue.java b/monitor-object/src/main/java/com/iluwatar/monitor/examples/Queue.java
new file mode 100644
index 000000000000..acdbc45a21b8
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/examples/Queue.java
@@ -0,0 +1,88 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor.examples;
+
+import com.iluwatar.monitor.AbstractMonitor;
+import com.iluwatar.monitor.Condition;
+
+/**
+ * FIFO Queue implementation using {@link AbstractMonitor}.
+ */
+public class Queue extends AbstractMonitor {
+
+ private final int capacity = 10;
+
+ private final Object[] queue = new Object[capacity];
+
+ private volatile int count = 0;
+
+ private volatile int front = 0;
+
+ /** Awaiting ensures: count < capacity. */
+ private final Condition notFull = makeCondition();
+
+ /** Awaiting ensures: count > 0. */
+ private final Condition notEmpty = makeCondition();
+
+ /**
+ * Method to pop the front element from queue.
+ * @return the top most element
+ */
+ public Object fetch() {
+ enter();
+ if (!(count > 0)) {
+ notEmpty.await();
+ assert count > 0;
+ }
+ count--;
+ front = (front + 1) % capacity;
+ assert count < capacity;
+ notFull.signal();
+ leave();
+ Object value = queue[front];
+ return value;
+ }
+
+ /**
+ * Method to push an element in queue.
+ * @param value the element to be pushed
+ */
+ public void deposit(Object value) {
+ enter();
+ if (!(count < capacity)) {
+ notFull.await();
+ assert count < capacity;
+ }
+ queue[(front + count) % capacity] = value;
+ count++;
+ assert count > 0;
+ notEmpty.signal();
+ leave();
+ }
+
+ @Override
+ protected boolean invariant() {
+ return 0 <= count && count <= capacity && 0 <= front && front < capacity;
+ }
+
+}
\ No newline at end of file
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/examples/VoteInterface.java b/monitor-object/src/main/java/com/iluwatar/monitor/examples/VoteInterface.java
new file mode 100644
index 000000000000..bed768034bef
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/examples/VoteInterface.java
@@ -0,0 +1,31 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor.examples;
+
+/**
+ * Monitor Example.
+ */
+
+public interface VoteInterface {
+ boolean castVoteAndWaitForResult(boolean vote);
+}
\ No newline at end of file
diff --git a/monitor-object/src/main/java/com/iluwatar/monitor/examples/VoteMonitor.java b/monitor-object/src/main/java/com/iluwatar/monitor/examples/VoteMonitor.java
new file mode 100644
index 000000000000..d8e888fcb8f8
--- /dev/null
+++ b/monitor-object/src/main/java/com/iluwatar/monitor/examples/VoteMonitor.java
@@ -0,0 +1,85 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor.examples;
+
+import com.iluwatar.monitor.AbstractMonitor;
+import com.iluwatar.monitor.Assertion;
+import com.iluwatar.monitor.Condition;
+import com.iluwatar.monitor.RunnableWithResult;
+
+/**
+ * Monitor Example.
+ */
+
+public class VoteMonitor extends AbstractMonitor implements VoteInterface {
+
+ private final int totalVotes;
+ private int votesFor = 0;
+ private int votesAgainst = 0;
+
+ private Condition electionDone = makeCondition(new Assertion() {
+ @Override
+ public boolean isTrue() {
+ return votesFor + votesAgainst == totalVotes;
+ }
+ });
+
+ public VoteMonitor(int n) {
+ assert n > 0;
+ this.totalVotes = n;
+ }
+
+ @Override
+ protected boolean invariant() {
+ return 0 <= votesFor && 0 <= votesAgainst && votesFor + votesAgainst < totalVotes;
+ }
+
+ /**
+ * Method to cast a vote and wait for the result.
+ */
+ public boolean castVoteAndWaitForResult(final boolean vote) {
+ return doWithin(new RunnableWithResult() {
+ public Boolean run() {
+ if (vote) {
+ votesFor++;
+ } else {
+ votesAgainst++;
+ }
+
+ electionDone.conditionalAwait();
+
+ // Assert: votesFor+votesAgainst == N
+ boolean result = votesFor > votesAgainst;
+
+ if (!electionDone.isEmpty()) {
+ electionDone.signalAndLeave();
+ } else {
+ votesFor = votesAgainst = 0;
+ }
+ // At this point the thread could be occupying
+ // the monitor, or not!
+ return result;
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/monitor-object/src/test/java/com/iluwatar/monitor/AssertionTest.java b/monitor-object/src/test/java/com/iluwatar/monitor/AssertionTest.java
new file mode 100644
index 000000000000..fb8751d0f19a
--- /dev/null
+++ b/monitor-object/src/test/java/com/iluwatar/monitor/AssertionTest.java
@@ -0,0 +1,66 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test Cases for Assertion.
+ */
+public class AssertionTest {
+ int varX = 0;
+ int varY = 0;
+
+ @Test
+ public void testAssertionTrue() {
+ Assertion a = new MyAssertion();
+ assertEquals(true, a.isTrue());
+ }
+
+ @Test
+ public void testAssertionFalse() {
+ Assertion a = new MyAssertion();
+ a.check();
+ varX = 1;
+ assertEquals(false, a.isTrue());
+ }
+
+ @Test
+ public void testAssertionError() {
+ assertThrows(AssertionError.class, () -> {
+ Assertion a = new MyAssertion();
+ a.check();
+ varX = 1;
+ a.check();
+ });
+ }
+
+ class MyAssertion extends Assertion {
+ public boolean isTrue() {
+ return varX == varY;
+ }
+ }
+}
\ No newline at end of file
diff --git a/monitor-object/src/test/java/com/iluwatar/monitor/ThreadSignalTest.java b/monitor-object/src/test/java/com/iluwatar/monitor/ThreadSignalTest.java
new file mode 100644
index 000000000000..b1b50694e82b
--- /dev/null
+++ b/monitor-object/src/test/java/com/iluwatar/monitor/ThreadSignalTest.java
@@ -0,0 +1,68 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+
+import com.iluwatar.monitor.examples.VoteInterface;
+import com.iluwatar.monitor.examples.VoteMonitor;
+
+/**
+ * Test Case for Thread Signaling.
+ */
+@TestInstance(Lifecycle.PER_CLASS)
+public class ThreadSignalTest {
+
+ private Voter v0;
+ private Voter v1;
+ private Voter v2;
+
+ /**
+ * Setup method for Test Case.
+ */
+ @BeforeAll
+ public void setUp() {
+ VoteInterface vm = new VoteMonitor(3);
+ v0 = new Voter0(vm);
+ v1 = new Voter1(vm);
+ v2 = new Voter2(vm);
+ }
+
+ @Test
+ public void testVotingResult() throws InterruptedException {
+ v0.start();
+ v1.start();
+ v2.start();
+ v0.join();
+ v1.join();
+ v2.join();
+ assertEquals("Passed", v0.getTestResult());
+ assertEquals("Passed", v1.getTestResult());
+ assertEquals("Passed", v2.getTestResult());
+ }
+}
\ No newline at end of file
diff --git a/monitor-object/src/test/java/com/iluwatar/monitor/Voter.java b/monitor-object/src/test/java/com/iluwatar/monitor/Voter.java
new file mode 100644
index 000000000000..549b906a5014
--- /dev/null
+++ b/monitor-object/src/test/java/com/iluwatar/monitor/Voter.java
@@ -0,0 +1,62 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+import com.iluwatar.monitor.examples.VoteInterface;
+
+abstract class Voter extends Thread {
+
+ private VoteInterface vm;
+
+ private String testResult;
+
+ public String getTestResult() {
+ return testResult;
+ }
+
+ public void setTestResult(String testResult) {
+ this.testResult = testResult;
+ }
+
+ Voter(VoteInterface vm) {
+ this.vm = vm;
+ }
+
+ public void run() {
+ for (int i = 0; i < 100; ++i) {
+ boolean vote = makeVote(i);
+ boolean consensus = vm.castVoteAndWaitForResult(vote);
+ boolean expected = i % 6 == 1 || i % 6 == 2 || i % 6 == 5;
+ if (expected != consensus) {
+ System.out.println("Failed");
+ setTestResult("Failed");
+ System.exit(1);
+ }
+ setTestResult("Passed");
+ System.out.println(i + ": " + consensus);
+ }
+ System.out.println("Done");
+ }
+
+ abstract boolean makeVote(int i);
+}
\ No newline at end of file
diff --git a/monitor-object/src/test/java/com/iluwatar/monitor/Voter0.java b/monitor-object/src/test/java/com/iluwatar/monitor/Voter0.java
new file mode 100644
index 000000000000..00332dbd8df0
--- /dev/null
+++ b/monitor-object/src/test/java/com/iluwatar/monitor/Voter0.java
@@ -0,0 +1,35 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+import com.iluwatar.monitor.examples.VoteInterface;
+
+class Voter0 extends Voter {
+ Voter0(VoteInterface vm) {
+ super(vm);
+ }
+
+ boolean makeVote(int i) {
+ return i % 2 == 1;
+ }
+}
\ No newline at end of file
diff --git a/monitor-object/src/test/java/com/iluwatar/monitor/Voter1.java b/monitor-object/src/test/java/com/iluwatar/monitor/Voter1.java
new file mode 100644
index 000000000000..f342e37accce
--- /dev/null
+++ b/monitor-object/src/test/java/com/iluwatar/monitor/Voter1.java
@@ -0,0 +1,35 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+import com.iluwatar.monitor.examples.VoteInterface;
+
+class Voter1 extends Voter {
+ Voter1(VoteInterface vm) {
+ super(vm);
+ }
+
+ boolean makeVote(int i) {
+ return i % 3 == 2;
+ }
+}
\ No newline at end of file
diff --git a/monitor-object/src/test/java/com/iluwatar/monitor/Voter2.java b/monitor-object/src/test/java/com/iluwatar/monitor/Voter2.java
new file mode 100644
index 000000000000..8975fc93b39f
--- /dev/null
+++ b/monitor-object/src/test/java/com/iluwatar/monitor/Voter2.java
@@ -0,0 +1,35 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.monitor;
+
+import com.iluwatar.monitor.examples.VoteInterface;
+
+class Voter2 extends Voter {
+ Voter2(VoteInterface vm) {
+ super(vm);
+ }
+
+ boolean makeVote(int i) {
+ return i % 3 != 0;
+ }
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 81763b6c1100..2dd7227247a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -162,7 +162,8 @@
trampoline
serverless
ambassador
- acyclic-visitor
+ acyclic-visitor
+ monitor-object
@@ -478,4 +479,4 @@
-
+
\ No newline at end of file