diff --git a/BuggyQueue/.classpath b/BuggyQueue/.classpath
deleted file mode 100644
index 18d70f02c..000000000
--- a/BuggyQueue/.classpath
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/BuggyQueue/.project b/BuggyQueue/.project
deleted file mode 100644
index 98aa6b7c1..000000000
--- a/BuggyQueue/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- BuggyQueue
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
-
-
diff --git a/BuggyQueue/build.gradle b/BuggyQueue/build.gradle
new file mode 100644
index 000000000..d88d747f6
--- /dev/null
+++ b/BuggyQueue/build.gradle
@@ -0,0 +1,15 @@
+group 'livelessons'
+version '1.0-SNAPSHOT'
+
+apply plugin: 'java'
+
+targetCompatibility = 1.8
+sourceCompatibility = 1.8
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testCompile group: 'junit', name: 'junit', version: '4.11'
+}
diff --git a/BuggyQueue/gradle/wrapper/gradle-wrapper.jar b/BuggyQueue/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..ca78035ef
Binary files /dev/null and b/BuggyQueue/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/BuggyQueue/gradle/wrapper/gradle-wrapper.properties b/BuggyQueue/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..be3fb022c
--- /dev/null
+++ b/BuggyQueue/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Aug 16 18:00:52 EDT 2016
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
diff --git a/BuggyQueue/gradlew b/BuggyQueue/gradlew
new file mode 100644
index 000000000..27309d923
--- /dev/null
+++ b/BuggyQueue/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/BuggyQueue/gradlew.bat b/BuggyQueue/gradlew.bat
new file mode 100644
index 000000000..832fdb607
--- /dev/null
+++ b/BuggyQueue/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/BuggyQueue/settings.gradle b/BuggyQueue/settings.gradle
new file mode 100644
index 000000000..96c454ba3
--- /dev/null
+++ b/BuggyQueue/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'BuggyQueue'
+
diff --git a/BuggyQueue/src/BuggyQueueTest.java b/BuggyQueue/src/BuggyQueueTest.java
deleted file mode 100644
index bb12349d7..000000000
--- a/BuggyQueue/src/BuggyQueueTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-import java.util.concurrent.*;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.List;
-
-/**
- * @class BuggyQueueTest
- *
- * @brief Test program for the SimpleQueue that induces race
- * conditions due to lack of synchronization.
- */
-public class BuggyQueueTest
-{
- /**
- * Maximum number of iterations.
- */
- private final static int mMaxIterations = 1000000;
-
- /**
- * Maximum size of the queue.
- */
- private final static int mQueueSize = 10;
-
- /**
- * Count the number of iterations.
- */
- private final static AtomicInteger mCount =
- new AtomicInteger(0);
-
- /**
- * @class ProducerThread
- *
- * @brief This producer runs in a separate Java Thread and passes
- * Strings to a consumer Thread via a shared BlockingQueue.
- */
- static class ProducerThread extends Thread {
- /**
- * This queue is shared with the consumer.
- */
- private final BQ mQueue;
-
- /**
- * Constructor initializes the BlockingQueue data
- * member.
- */
- ProducerThread(BQ blockingQueue) {
- mQueue = blockingQueue;
- }
-
- /**
- * This method runs in a separate Java Thread and passes
- * Strings to a consumer Thread via a shared BlockingQueue.
- */
- public void run(){
- try {
- for(int i = 0; i < mMaxIterations; i++) {
- mCount.incrementAndGet();
-
- // Calls the put() method.
- mQueue.put(Integer.toString(i));
- }
- } catch (InterruptedException e) {
- System.out.println("InterruptedException caught");
- }
- }
- }
-
- /**
- * @class ConsumerThread
- *
- * @brief This consumer runs in a separate Java Thread and
- * receives Strings from a producer Thread via a shared
- * BlockingQueue.
- */
- static class ConsumerThread extends Thread {
- /**
- * This queue is shared with the producer.
- */
- private final BQ mQueue;
-
- /**
- * Constructor initializes the BlockingQueue data member.
- */
- ConsumerThread(BQ blockingQueue) {
- mQueue = blockingQueue;
- }
-
- /**
- * This method runs in a separate Java Thread and receives
- * Strings from a producer Thread via a shared BlockingQueue.
- */
- public void run(){
- Object s = null;
- try {
- for(int i = 0; i < mMaxIterations; i++) {
- // Calls the take() method.
- s = mQueue.take();
-
- mCount.decrementAndGet();
-
- if((i % (mMaxIterations / 10)) == 0)
- System.out.println(s == null ? "" : s);
- }
- } catch (InterruptedException e) {
- System.out.println("InterruptedException caught");
- }
- System.out.println("Final size of the queue is "
- + mQueue.size()
- + "\nmCount is "
- + mCount.get()
- + "\nFinal value is "
- + s);
- }
- }
-
- /**
- * Main entry point that tests the SimpleQueue class.
- */
- public static void main(String argv[]) {
- final SimpleQueue simpleQueue =
- new SimpleQueue(); // (mQueueSize);
-
- try {
- // Create a ProducerThread.
- Thread producer =
- new ProducerThread(simpleQueue);
-
- // Create a ConsumerThread.
- Thread consumer =
- new ConsumerThread(simpleQueue);
-
- // Run both Threads concurrently.
- producer.start();
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {}
-
- consumer.start();
-
- // Wait for both Threads to stop.
- producer.join();
- consumer.join();
- } catch (Exception e) {
- System.out.println("caught exception");
- }
- }
-}
diff --git a/BuggyQueue/src/SimpleQueue.java b/BuggyQueue/src/SimpleQueue.java
deleted file mode 100644
index fea73deab..000000000
--- a/BuggyQueue/src/SimpleQueue.java
+++ /dev/null
@@ -1,163 +0,0 @@
-import java.util.List;
-import java.util.concurrent.CyclicBarrier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/*
- * @class SimpleQueue
- *
- * @brief Defines an implementation of the BlockingQueue interface
- * that (intentially) doesn't work properly when accessed via
- * multiple threads since it's not synchronized properly.
- */
-class SimpleQueue implements BlockingQueue {
- /**
- * The queue consists of a List of E's.
- */
- private List mList = new ArrayList();
-
- /**
- * The maximum capacity of the queue or Integer.MAX_VALUE if none.
- */
- private final int mCapacity;
-
- /**
- * Create a SimpleBlocking queue with a capacity of
- * Integer.MAX_VALUE.
- */
- public SimpleQueue() {
- this(Integer.MAX_VALUE);
- }
-
- /**
- * Create a SimpleBlocking queue with the given capacity.
- */
- public SimpleQueue(int capacity) {
- if (capacity <= 0)
- throw new IllegalArgumentException();
- mCapacity = capacity;
- mList = new ArrayList();
- }
-
- /**
- * True if the queue is empty.
- */
- public boolean isEmpty() {
- return mList.size() == 0;
- }
-
- /**
- * Returns true if the queue is full, else false.
- */
- private boolean isFull() {
- return mList.size() == mCapacity;
- }
-
- /**
- * Add a new E to the end of the queue.
- */
- public void put(E msg) throws InterruptedException {
- if (isFull() == false)
- mList.add(msg);
- }
-
- /**
- * Remove the E at the front of the queue.
- */
- public E take() throws InterruptedException {
- if (isEmpty() == false)
- return mList.remove(0);
- else
- return null;
- }
-
- /**
- * Returns the number of elements in this queue.
- */
- public int size() {
- return mList.size();
- }
-
- /**
- * All these methods are inherited from the BlockingQueue
- * interface. They are defined as no-ops to ensure the "Buggyness"
- * of this class ;-)
- */
- public int drainTo(Collection super E> c) {
- return 0;
- }
- public int drainTo(Collection super E> c, int maxElements) {
- return 0;
- }
- public boolean contains(Object o) {
- return false;
- }
- public boolean remove(Object o) {
- return false;
- }
- public int remainingCapacity() {
- return 0;
- }
- public E poll() {
- return null;
- }
- public E poll(long timeout, TimeUnit unit) throws InterruptedException {
- return take();
- }
- public E peek() {
- return null;
- }
- public boolean offer(E e) {
- return false;
- }
- public boolean offer(E e, long timeout, TimeUnit unit) {
- try {
- put(e);
- }
- catch (InterruptedException ex) {
- // Just swallow this exception for this simple (buggy) test.
- }
- return true;
- }
- public boolean add(E e) {
- return false;
- }
- public E element() {
- return null;
- }
- public E remove() {
- return null;
- }
- public void clear() {
- }
- public boolean retainAll(Collection> collection) {
- return false;
- }
- public boolean removeAll(Collection> collection) {
- return false;
- }
- public boolean addAll(Collection extends E> collection) {
- return false;
- }
- public boolean containsAll(Collection> collection) {
- return false;
- }
- public Object[] toArray() {
- return null;
- }
- public T[] toArray(T[] array) {
- return null;
- }
- public Iterator iterator() {
- return null;
- }
-}
-
-
-
-
-
-
diff --git a/BuggyQueue/src/main/java/edu/vandy/BoundedQueue.java b/BuggyQueue/src/main/java/edu/vandy/BoundedQueue.java
new file mode 100644
index 000000000..c2eda31e3
--- /dev/null
+++ b/BuggyQueue/src/main/java/edu/vandy/BoundedQueue.java
@@ -0,0 +1,73 @@
+package edu.vandy;
+
+/**
+ * Defines an interface for a bounded queue.
+ */
+public interface BoundedQueue {
+ /**
+ * Inserts the specified element into this queue, waiting if
+ * necessary for space to become available.
+ *
+ * @param e the element to add
+ * @throws InterruptedException if interrupted while waiting
+ */
+ default void put(E e)
+ throws InterruptedException {
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, waiting if necessary
+ * until an element becomes available.
+ *
+ * @return the head of this queue
+ * @throws InterruptedException if interrupted while waiting
+ */
+ default E take()
+ throws InterruptedException {
+ return null;
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, or returns {@code
+ * null} if this queue is empty.
+ *
+ * @return the head of this queue, or {@code null} if this queue is empty
+ */
+ default E poll() {
+ return null;
+ }
+
+ /**
+ * Inserts the specified element into this queue if it is possible to do
+ * so immediately without violating capacity restrictions, returning
+ * {@code true} upon success and {@code false} if no space is currently
+ * available.
+ *
+ * @return {@code true} if the element was added to this queue, else
+ * {@code false}
+ */
+ default boolean offer(E e) {
+ return false;
+ }
+
+ /**
+ * Returns true if this queue contains no elements, else false.
+ *
+ * @return true if this queue contains no elements, else false.
+ */
+ boolean isEmpty();
+
+ /**
+ * Returns true if this queue is full, else false.
+ *
+ * @return true if this queue is full, else false.
+ */
+ boolean isFull();
+
+ /**
+ * Returns the number of elements in this queue.
+ *
+ * @return the number of elements in this collection
+ */
+ int size();
+}
diff --git a/BuggyQueue/src/main/java/edu/vandy/BuggyQueue.java b/BuggyQueue/src/main/java/edu/vandy/BuggyQueue.java
new file mode 100644
index 000000000..b9d8058c6
--- /dev/null
+++ b/BuggyQueue/src/main/java/edu/vandy/BuggyQueue.java
@@ -0,0 +1,106 @@
+package edu.vandy;
+
+import java.util.List;
+import java.util.concurrent.CyclicBarrier;
+import java.util.LinkedList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+
+/*
+ * Defines an implementation of the BoundedQueue interface that
+ * (intentially) doesn't work properly when accessed via multiple
+ * threads since it's not synchronized properly.
+ */
+class BuggyQueue
+ implements BoundedQueue {
+ /**
+ * The queue consists of a LinkedList of E's.
+ */
+ private List mList = new LinkedList<>();
+
+ /**
+ * The maximum capacity of the queue or Integer.MAX_VALUE if none.
+ */
+ private final int mCapacity;
+
+ /**
+ * Create a BuggyQueue with a capacity of Integer.MAX_VALUE.
+ */
+ public BuggyQueue() {
+ this(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Create a BuggyQueue with the given capacity.
+ */
+ public BuggyQueue(int capacity) {
+ if (capacity <= 0)
+ throw new IllegalArgumentException();
+ mCapacity = capacity;
+ mList = new LinkedList<>();
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, or returns {@code
+ * null} if this queue is empty.
+ *
+ * @return the head of this queue, or {@code null} if this queue is empty
+ */
+ public E poll() {
+ if (!isEmpty())
+ return mList.remove(0);
+ else
+ return null;
+ }
+
+ /**
+ * Inserts the specified element into this queue if it is possible to do
+ * so immediately without violating capacity restrictions, returning
+ * {@code true} upon success and {@code false} if no space is currently
+ * available.
+ *
+ * @return {@code true} if the element was added to this queue, else
+ * {@code false}
+ */
+ public boolean offer(E e) {
+ if (!isFull()) {
+ mList.add(e);
+ return true;
+ } else
+ return false;
+ }
+
+ /**
+ * Returns true if this queue contains no elements, else false.
+ *
+ * @return true if this queue contains no elements, else false.
+ */
+ public boolean isEmpty() {
+ return mList.size() == 0;
+ }
+
+ /**
+ * Returns true if this queue is full, else false.
+ *
+ * @return true if this queue is full, else false.
+ */
+ public boolean isFull() {
+ return mList.size() == mCapacity;
+ }
+
+ /**
+ * Returns the number of elements in this queue.
+ *
+ * @return the number of elements in this collection
+ */
+ public int size() {
+ return mList.size();
+ }
+}
+
+
+
+
+
+
diff --git a/BuggyQueue/src/test/java/edu/vandy/BuggyQueueTest.java b/BuggyQueue/src/test/java/edu/vandy/BuggyQueueTest.java
new file mode 100644
index 000000000..2788c78a4
--- /dev/null
+++ b/BuggyQueue/src/test/java/edu/vandy/BuggyQueueTest.java
@@ -0,0 +1,169 @@
+package edu.vandy;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Test;
+
+/**
+ * Test program for the BuggyQueue that induces race conditions due to
+ * lack of synchronization.
+ */
+public class BuggyQueueTest {
+ /**
+ * Maximum number of iterations.
+ */
+ private final static int mMaxIterations = 100000;
+
+ /**
+ * Maximum size of the queue.
+ */
+ private final static int sQUEUE_SIZE = 10;
+
+ /**
+ * Count the number of iterations.
+ */
+ private final static AtomicInteger mCount =
+ new AtomicInteger(0);
+
+ /**
+ * This producer runs in a separate Java thread and passes strings
+ * to a consumer thread via a shared BoundedQueue.
+ */
+ private static class Producer>
+ implements Runnable {
+ /**
+ * This queue is shared with the consumer.
+ */
+ private final BQ mQueue;
+
+ /**
+ * Constructor initializes the BoundedQueue data member.
+ */
+ Producer(BQ blockingQueue) {
+ mQueue = blockingQueue;
+ }
+
+ /**
+ * This method runs in a separate Java thread and passes
+ * strings to a consumer thread via a shared BoundedQueue.
+ */
+ public void run() {
+ for (int i = 0; i < mMaxIterations; ) {
+ // Calls the offer() method.
+ if (mQueue.offer(i)) {
+ i++;
+ mCount.incrementAndGet();
+ } else
+ Thread.yield();
+ }
+ }
+ }
+
+ /**
+ * This consumer runs in a separate Java thread and receives
+ * strings from a producer thread via a shared BoundedQueue.
+ */
+ private static class Consumer>
+ implements Runnable {
+ /**
+ * This queue is shared with the producer.
+ */
+ private final BQ mQueue;
+
+ /**
+ * Constructor initializes the BoundedQueue data member.
+ */
+ Consumer(BQ blockingQueue) {
+ mQueue = blockingQueue;
+ }
+
+ /**
+ * This method runs in a separate Java thread and receives
+ * strings from a producer thread via a shared BoundedQueue.
+ */
+ public void run() {
+ Integer integer = null;
+ int nullCount = 0;
+
+ // Get the first item from the queue.
+ Integer previous = null;
+
+ // Get the first non-null value.
+ while ((previous = mQueue.poll()) == null)
+ continue;
+
+ mCount.decrementAndGet();
+
+ for (int i = 1; i < mMaxIterations; ) {
+ // Try to get the next integer.
+ integer = mQueue.poll();
+
+ // Only update the state if we get a non-null
+ // value from take().
+ if (integer != null) {
+ // Make sure the entries are ordered.
+ assertEquals(previous + 1, integer.intValue());
+ previous = integer;
+
+ if ((i % (mMaxIterations / 10)) == 0)
+ System.out.println(integer);
+ mCount.decrementAndGet();
+ i++;
+
+ } else {
+ nullCount++;
+ Thread.yield();
+ }
+ }
+
+ assertEquals(0, mCount.get());
+
+ System.out.println("Final size of the queue is "
+ + mQueue.size()
+ + "\nmCount is "
+ + mCount.get()
+ + "\nFinal value is "
+ + integer
+ + "\nnumber of null returns from take() is "
+ + nullCount
+ + "\nmCount + nullCount is "
+ + (mCount.get() + nullCount));
+ }
+ }
+
+ /**
+ * Main entry point that tests the SimpleQueue class.
+ */
+ @Test(timeout=10000)
+ public void testBuggyQueue() {
+ final BuggyQueue buggyQueue =
+ new BuggyQueue<>(sQUEUE_SIZE);
+
+ try {
+ // Create producer and consumer threads.
+ Thread[] threads = new Thread[] {
+ new Thread(new Producer<>(buggyQueue)),
+ new Thread(new Consumer<>(buggyQueue))
+ };
+
+ // Record the start time.
+ long startTime = System.nanoTime();
+
+ // Start all the threads.
+ for (Thread thread : threads)
+ thread.start();
+
+ // Wait for all threads to stop.
+ for (Thread thread : threads)
+ thread.join();
+
+ System.out.println("test ran in "
+ + (System.nanoTime() - startTime) / 1_000_000
+ + " msecs");
+ } catch (Exception e) {
+ System.out.println("caught exception");
+ }
+ }
+}
diff --git a/BusySynchronizedQueue/.classpath b/BusySynchronizedQueue/.classpath
deleted file mode 100644
index 18d70f02c..000000000
--- a/BusySynchronizedQueue/.classpath
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/BusySynchronizedQueue/.project b/BusySynchronizedQueue/.project
deleted file mode 100644
index 40c74dd7f..000000000
--- a/BusySynchronizedQueue/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- BusySynchronizedQueue
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
-
-
diff --git a/BusySynchronizedQueue/build.gradle b/BusySynchronizedQueue/build.gradle
new file mode 100644
index 000000000..d88d747f6
--- /dev/null
+++ b/BusySynchronizedQueue/build.gradle
@@ -0,0 +1,15 @@
+group 'livelessons'
+version '1.0-SNAPSHOT'
+
+apply plugin: 'java'
+
+targetCompatibility = 1.8
+sourceCompatibility = 1.8
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testCompile group: 'junit', name: 'junit', version: '4.11'
+}
diff --git a/BusySynchronizedQueue/gradle/wrapper/gradle-wrapper.jar b/BusySynchronizedQueue/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..ca78035ef
Binary files /dev/null and b/BusySynchronizedQueue/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/BusySynchronizedQueue/gradle/wrapper/gradle-wrapper.properties b/BusySynchronizedQueue/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..be3fb022c
--- /dev/null
+++ b/BusySynchronizedQueue/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Aug 16 18:00:52 EDT 2016
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
diff --git a/BusySynchronizedQueue/gradlew b/BusySynchronizedQueue/gradlew
new file mode 100644
index 000000000..27309d923
--- /dev/null
+++ b/BusySynchronizedQueue/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/BusySynchronizedQueue/gradlew.bat b/BusySynchronizedQueue/gradlew.bat
new file mode 100644
index 000000000..832fdb607
--- /dev/null
+++ b/BusySynchronizedQueue/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/BusySynchronizedQueue/settings.gradle b/BusySynchronizedQueue/settings.gradle
new file mode 100644
index 000000000..2768ef94f
--- /dev/null
+++ b/BusySynchronizedQueue/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'BusySynchronizedQueue'
+
diff --git a/BusySynchronizedQueue/src/BusySynchronizedQueue.java b/BusySynchronizedQueue/src/BusySynchronizedQueue.java
deleted file mode 100644
index a245c9dcf..000000000
--- a/BusySynchronizedQueue/src/BusySynchronizedQueue.java
+++ /dev/null
@@ -1,163 +0,0 @@
-import java.util.List;
-import java.util.concurrent.CyclicBarrier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/*
- * @class BusySynchronizedQueue
- *
- * @brief Defines an implementation of the BlockingQueue interface
- * that works properly when accessed via multiple threads since
- * it's synchronized properly, but is inefficient since it
- * "busy waits".
- */
-class BusySynchronizedQueue implements BlockingQueue {
- /**
- * The queue consists of a List of E's.
- */
- private List mList = new ArrayList();
-
- /**
- * The maximum capacity of the queue or Integer.MAX_VALUE if none.
- */
- private final int mCapacity;
-
- /**
- * Create a SimpleBlocking queue with a capacity of
- * Integer.MAX_VALUE.
- */
- public BusySynchronizedQueue() {
- this(Integer.MAX_VALUE);
- }
-
- /**
- * Create a SimpleBlocking queue with the given capacity.
- */
- public BusySynchronizedQueue(int capacity) {
- if (capacity <= 0)
- throw new IllegalArgumentException();
- mCapacity = capacity;
- mList = new ArrayList();
- }
-
- /**
- * True if the queue is empty.
- */
- public synchronized boolean isEmpty() {
- return mList.size() == 0;
- }
-
- /**
- * Returns true if the queue is full, else false.
- */
- private synchronized boolean isFull() {
- return mList.size() == mCapacity;
- }
-
- /**
- * Add a new E to the end of the queue.
- */
- public synchronized void put(E msg) throws InterruptedException {
- if (isFull() == false)
- mList.add(msg);
- }
-
- /**
- * Remove the E at the front of the queue.
- */
- public synchronized E take() throws InterruptedException {
- if (isEmpty() == false)
- return mList.remove(0);
- else
- return null;
- }
-
- /**
- * Returns the number of elements in this queue.
- */
- public synchronized int size() {
- return mList.size();
- }
-
- /**
- * All these methods are inherited from the BlockingQueue
- * interface. All are defined as no-ops for simplicity.
- */
- public int drainTo(Collection super E> c) {
- return 0;
- }
- public int drainTo(Collection super E> c, int maxElements) {
- return 0;
- }
- public boolean contains(Object o) {
- return false;
- }
- public boolean remove(Object o) {
- return false;
- }
- public int remainingCapacity() {
- return 0;
- }
- public E poll() {
- return null;
- }
- public E poll(long timeout, TimeUnit unit) throws InterruptedException {
- return take();
- }
- public E peek() {
- return null;
- }
- public boolean offer(E e) {
- return false;
- }
- public boolean offer(E e, long timeout, TimeUnit unit) {
- try {
- put(e);
- }
- catch (InterruptedException ex) {
- // Just swallow this exception for this simple (buggy) test.
- }
- return true;
- }
- public boolean add(E e) {
- return false;
- }
- public E element() {
- return null;
- }
- public E remove() {
- return null;
- }
- public void clear() {
- }
- public boolean retainAll(Collection> collection) {
- return false;
- }
- public boolean removeAll(Collection> collection) {
- return false;
- }
- public boolean addAll(Collection extends E> collection) {
- return false;
- }
- public boolean containsAll(Collection> collection) {
- return false;
- }
- public Object[] toArray() {
- return null;
- }
- public T[] toArray(T[] array) {
- return null;
- }
- public Iterator iterator() {
- return null;
- }
-}
-
-
-
-
-
-
diff --git a/BusySynchronizedQueue/src/BusySynchronizedQueueTest.java b/BusySynchronizedQueue/src/BusySynchronizedQueueTest.java
deleted file mode 100644
index 0248cc503..000000000
--- a/BusySynchronizedQueue/src/BusySynchronizedQueueTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-import java.util.concurrent.*;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.List;
-
-/**
- * @class BusySynchronizedQueueTest
- *
- * @brief Test program for the BusySynchronizedQueue that is
- * inefficient due to "busy waiting".
- */
-public class BusySynchronizedQueueTest
-{
- /**
- * Maximum number of iterations.
- */
- private final static int mMaxIterations = 1000000;
-
- /**
- * Maximum size of the queue.
- */
- private final static int mQueueSize = 10;
-
- /**
- * Count the number of iterations.
- */
- private final static AtomicInteger mCount =
- new AtomicInteger(0);
-
- /**
- * @class ProducerThread
- *
- * @brief This producer runs in a separate Java Thread and passes
- * Strings to a consumer Thread via a shared BlockingQueue.
- */
- static class ProducerThread extends Thread {
- /**
- * This queue is shared with the consumer.
- */
- private final BQ mQueue;
-
- /**
- * Constructor initializes the BlockingQueue data
- * member.
- */
- ProducerThread(BQ blockingQueue) {
- mQueue = blockingQueue;
- }
-
- /**
- * This method runs in a separate Java Thread and passes
- * Strings to a consumer Thread via a shared BlockingQueue.
- */
- public void run(){
- try {
- for(int i = 0; i < mMaxIterations; i++) {
- mCount.incrementAndGet();
-
- // Calls the put() method.
- mQueue.put(Integer.toString(i));
- }
- } catch (InterruptedException e) {
- System.out.println("InterruptedException caught");
- }
- }
- }
-
- /**
- * @class ConsumerThread
- *
- * @brief This consumer runs in a separate Java Thread and
- * receives Strings from a producer Thread via a shared
- * BlockingQueue.
- */
- static class ConsumerThread extends Thread {
- /**
- * This queue is shared with the producer.
- */
- private final BQ mQueue;
-
- /**
- * Constructor initializes the BlockingQueue data member.
- */
- ConsumerThread(BQ blockingQueue) {
- mQueue = blockingQueue;
- }
-
- /**
- * This method runs in a separate Java Thread and receives
- * Strings from a producer Thread via a shared BlockingQueue.
- */
- public void run(){
- Object s = null;
- try {
- for(int i = 0; i < mMaxIterations; i++) {
- // Calls the take() method.
- s = mQueue.take();
-
- mCount.decrementAndGet();
-
- if ((i % (mMaxIterations / 10)) == 0)
- System.out.println(s == null ? "" : s);
- }
- } catch (InterruptedException e) {
- System.out.println("InterruptedException caught");
- }
- System.out.println("Final size of the queue is "
- + mQueue.size()
- + "\nmCount is "
- + mCount.get()
- + "\nFinal value is "
- + s);
- }
- }
-
- /**
- * Main entry point that tests the BusySynchronizedQueue class.
- */
- public static void main(String argv[]) {
- final BusySynchronizedQueue busySynchronizedQueue =
- new BusySynchronizedQueue(); // (mQueueSize);
-
- try {
- // Create a ProducerThread.
- Thread producer =
- new ProducerThread(busySynchronizedQueue);
-
- // Create a ConsumerThread.
- Thread consumer =
- new ConsumerThread(busySynchronizedQueue);
-
- // Run both Threads concurrently.
- producer.start();
-
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {}
-
- consumer.start();
-
- // Wait for both Threads to stop.
- producer.join();
- consumer.join();
- } catch (Exception e) {
- System.out.println("caught exception");
- }
- }
-}
diff --git a/BusySynchronizedQueue/src/main/java/edu/vandy/BoundedQueue.java b/BusySynchronizedQueue/src/main/java/edu/vandy/BoundedQueue.java
new file mode 100644
index 000000000..c2eda31e3
--- /dev/null
+++ b/BusySynchronizedQueue/src/main/java/edu/vandy/BoundedQueue.java
@@ -0,0 +1,73 @@
+package edu.vandy;
+
+/**
+ * Defines an interface for a bounded queue.
+ */
+public interface BoundedQueue {
+ /**
+ * Inserts the specified element into this queue, waiting if
+ * necessary for space to become available.
+ *
+ * @param e the element to add
+ * @throws InterruptedException if interrupted while waiting
+ */
+ default void put(E e)
+ throws InterruptedException {
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, waiting if necessary
+ * until an element becomes available.
+ *
+ * @return the head of this queue
+ * @throws InterruptedException if interrupted while waiting
+ */
+ default E take()
+ throws InterruptedException {
+ return null;
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, or returns {@code
+ * null} if this queue is empty.
+ *
+ * @return the head of this queue, or {@code null} if this queue is empty
+ */
+ default E poll() {
+ return null;
+ }
+
+ /**
+ * Inserts the specified element into this queue if it is possible to do
+ * so immediately without violating capacity restrictions, returning
+ * {@code true} upon success and {@code false} if no space is currently
+ * available.
+ *
+ * @return {@code true} if the element was added to this queue, else
+ * {@code false}
+ */
+ default boolean offer(E e) {
+ return false;
+ }
+
+ /**
+ * Returns true if this queue contains no elements, else false.
+ *
+ * @return true if this queue contains no elements, else false.
+ */
+ boolean isEmpty();
+
+ /**
+ * Returns true if this queue is full, else false.
+ *
+ * @return true if this queue is full, else false.
+ */
+ boolean isFull();
+
+ /**
+ * Returns the number of elements in this queue.
+ *
+ * @return the number of elements in this collection
+ */
+ int size();
+}
diff --git a/BusySynchronizedQueue/src/main/java/edu/vandy/BusySynchronizedQueue.java b/BusySynchronizedQueue/src/main/java/edu/vandy/BusySynchronizedQueue.java
new file mode 100644
index 000000000..3a8909441
--- /dev/null
+++ b/BusySynchronizedQueue/src/main/java/edu/vandy/BusySynchronizedQueue.java
@@ -0,0 +1,121 @@
+package edu.vandy;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+
+/*
+ * Implements the BoundedQueue interface that works properly when
+ * accessed via multiple threads since it's synchronized properly, but
+ * is inefficient since due to its "busy waiting".
+ */
+class BusySynchronizedQueue
+ implements BoundedQueue {
+ /**
+ * The queue consists of a LinkedList of E's.
+ */
+ private List mList = new LinkedList<>();
+
+ /**
+ * The maximum capacity of the queue or Integer.MAX_VALUE if none.
+ */
+ private final int mCapacity;
+
+ /**
+ * Create a SimpleBlocking queue with a capacity of
+ * Integer.MAX_VALUE.
+ */
+ public BusySynchronizedQueue() {
+ this(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Create a SimpleBlocking queue with the given capacity.
+ */
+ public BusySynchronizedQueue(int capacity) {
+ if (capacity <= 0)
+ throw new IllegalArgumentException();
+ mCapacity = capacity;
+ mList = new LinkedList<>();
+ }
+
+ /**
+ * Returns true if this queue contains no elements, else false.
+ *
+ * @return true if this queue contains no elements, else false.
+ */
+ @Override
+ public boolean isEmpty() {
+ synchronized(this) {
+ return mList.size() == 0;
+ }
+ }
+
+ /**
+ * Returns true if this queue is full, else false.
+ *
+ * @return true if this queue is full, else false.
+ */
+ @Override
+ public boolean isFull() {
+ synchronized(this) {
+ return mList.size() == mCapacity;
+ }
+ }
+
+ /**
+ * Returns the number of elements in this queue.
+ *
+ * @return the number of elements in this collection
+ */
+ @Override
+ public int size() {
+ synchronized(this) {
+ return mList.size();
+ }
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, or returns {@code
+ * null} if this queue is empty.
+ *
+ * @return the head of this queue, or {@code null} if this queue is empty
+ */
+ @Override
+ public E poll() {
+ synchronized(this) {
+ if (!isEmpty())
+ return mList.remove(0);
+ else
+ return null;
+ }
+ }
+
+ /**
+ * Inserts the specified element into this queue if it is possible to do
+ * so immediately without violating capacity restrictions, returning
+ * {@code true} upon success and {@code false} if no space is currently
+ * available.
+ *
+ * @return {@code true} if the element was added to this queue, else
+ * {@code false}
+ */
+ @Override
+ public boolean offer(E e) {
+ synchronized (this) {
+ if (!isFull()) {
+ mList.add(e);
+ return true;
+ } else
+ return false;
+ }
+ }
+}
+
+
+
+
+
+
diff --git a/BusySynchronizedQueue/src/test/java/edu/vandy/BusySynchronizedQueueTest.java b/BusySynchronizedQueue/src/test/java/edu/vandy/BusySynchronizedQueueTest.java
new file mode 100644
index 000000000..2bfb3931f
--- /dev/null
+++ b/BusySynchronizedQueue/src/test/java/edu/vandy/BusySynchronizedQueueTest.java
@@ -0,0 +1,170 @@
+package edu.vandy;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Test;
+
+/**
+ * Test program for the BusySynchronizedQueue that is inefficient due
+ * to its use of "busy waiting".
+ */
+public class BusySynchronizedQueueTest {
+ /**
+ * Maximum number of iterations.
+ */
+ private final static int mMaxIterations = 100000;
+
+ /**
+ * Maximum size of the queue.
+ */
+ private final static int sQUEUE_SIZE = 10;
+
+ /**
+ * Count the number of iterations.
+ */
+ private final static AtomicInteger mCount =
+ new AtomicInteger(0);
+
+ /**
+ * This producer runs in a separate Java thread and passes strings
+ * to a consumer thread via a shared BoundedBlockingQueue.
+ */
+ private static class Producer>
+ implements Runnable {
+ /**
+ * This queue is shared with the consumer.
+ */
+ private final BQ mQueue;
+
+ /**
+ * Constructor initializes the @a blockingQueue field.
+ */
+ Producer(BQ blockingQueue) {
+ mQueue = blockingQueue;
+ }
+
+ /**
+ * This method runs in a Java thread and passes strings to a
+ * consumer thread via a shared BoundedBlockingQueue.
+ */
+ public void run() {
+ for(int i = 0; i < mMaxIterations; ) {
+ // Calls the offer() method.
+ if (mQueue.offer(i)) {
+ i++;
+ mCount.incrementAndGet();
+ }
+ }
+ }
+ }
+
+ /**
+ * This consumer runs in a Java thread and receives strings from a
+ * producer thread via a shared BoundedBlockingQueue.
+ */
+ private static class Consumer>
+ implements Runnable {
+ /**
+ * This queue is shared with the producer.
+ */
+ private final BQ mQueue;
+
+ /**
+ * Constructor initializes the @a blockingQueue data member.
+ */
+ Consumer(BQ blockingQueue) {
+ mQueue = blockingQueue;
+ }
+
+ /**
+ * This method runs in a Java thread and receives integers
+ * from a producer thread via a shared BoundedBlockingQueue.
+ */
+ public void run() {
+ Integer integer = null;
+ int nullCount = 0;
+
+ // Get the first item from the queue.
+ Integer previous;
+
+ // Get the first non-null value.
+ while ((previous = mQueue.poll()) == null)
+ continue;
+
+ mCount.decrementAndGet();
+
+ for (int i = 1; i < mMaxIterations; ) {
+ // Try to get the next integer.
+ integer = mQueue.poll();
+
+ // Only update the state if we get a non-null
+ // value from take().
+ if (integer != null) {
+ if ((i % (mMaxIterations / 10)) == 0)
+ System.out.println(integer);
+
+ mCount.decrementAndGet();
+ i++;
+
+ // Make sure the entries are ordered.
+ assertEquals(previous + 1, integer.intValue());
+ previous = integer;
+
+ } else {
+ nullCount++;
+ // Thread.yield();
+ }
+ }
+
+ assertEquals(0, mCount.get());
+
+ System.out.println("Final size of the queue is "
+ + mQueue.size()
+ + "\nmCount is "
+ + mCount.get()
+ + "\nFinal value is "
+ + integer
+ + "\nnumber of null returns from take() is "
+ + nullCount
+ + "\nmCount + nullCount is "
+ + (mCount.get() + nullCount));
+ }
+ }
+
+ /**
+ * Main entry point that tests the BusySynchronizedQueue class.
+ */
+ @Test
+ public void testBusySynchronizedQueue() {
+ final BusySynchronizedQueue busySynchronizedQueue =
+ new BusySynchronizedQueue<>(sQUEUE_SIZE);
+
+ try {
+ // Create producer and consumer threads.
+ Thread[] threads = new Thread[] {
+ new Thread(new Producer<>(busySynchronizedQueue)),
+ new Thread(new Consumer<>(busySynchronizedQueue))
+ };
+
+ // Record the start time.
+ long startTime = System.nanoTime();
+
+ // Start all the threads.
+ for (Thread thread : threads)
+ thread.start();
+
+ // Wait for all threads to stop.
+ for (Thread thread : threads)
+ thread.join();
+
+ System.out.println("test ran in "
+ + (System.nanoTime() - startTime) / 1_000_000
+ + " msecs");
+ } catch (Exception e) {
+ System.out.println("caught exception");
+ }
+ }
+}
diff --git a/SimpleBlockingQueue/.classpath b/SimpleBlockingQueue/.classpath
deleted file mode 100644
index 18d70f02c..000000000
--- a/SimpleBlockingQueue/.classpath
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/SimpleBlockingQueue/.project b/SimpleBlockingQueue/.project
deleted file mode 100644
index d5d34236a..000000000
--- a/SimpleBlockingQueue/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- SimpleBlockingQueue
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
-
-
diff --git a/SimpleBlockingQueue/build.gradle b/SimpleBlockingQueue/build.gradle
new file mode 100644
index 000000000..d88d747f6
--- /dev/null
+++ b/SimpleBlockingQueue/build.gradle
@@ -0,0 +1,15 @@
+group 'livelessons'
+version '1.0-SNAPSHOT'
+
+apply plugin: 'java'
+
+targetCompatibility = 1.8
+sourceCompatibility = 1.8
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testCompile group: 'junit', name: 'junit', version: '4.11'
+}
diff --git a/SimpleBlockingQueue/gradle/wrapper/gradle-wrapper.jar b/SimpleBlockingQueue/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..ca78035ef
Binary files /dev/null and b/SimpleBlockingQueue/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/SimpleBlockingQueue/gradle/wrapper/gradle-wrapper.properties b/SimpleBlockingQueue/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..be3fb022c
--- /dev/null
+++ b/SimpleBlockingQueue/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Aug 16 18:00:52 EDT 2016
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
diff --git a/SimpleBlockingQueue/gradlew b/SimpleBlockingQueue/gradlew
new file mode 100644
index 000000000..27309d923
--- /dev/null
+++ b/SimpleBlockingQueue/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/SimpleBlockingQueue/gradlew.bat b/SimpleBlockingQueue/gradlew.bat
new file mode 100644
index 000000000..832fdb607
--- /dev/null
+++ b/SimpleBlockingQueue/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/SimpleBlockingQueue/settings.gradle b/SimpleBlockingQueue/settings.gradle
new file mode 100644
index 000000000..55df1dc07
--- /dev/null
+++ b/SimpleBlockingQueue/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'SimpleBlockingBoundedQueue'
+
diff --git a/SimpleBlockingQueue/src/SimpleBlockingQueue.java b/SimpleBlockingQueue/src/SimpleBlockingQueue.java
deleted file mode 100644
index 79ce09321..000000000
--- a/SimpleBlockingQueue/src/SimpleBlockingQueue.java
+++ /dev/null
@@ -1,189 +0,0 @@
-import java.util.List;
-import java.util.concurrent.CyclicBarrier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/*
- * @class SimpleBlockingQueue
- *
- * @brief Defines an implementation of the BlockingQueue interface
- * that works properly when accessed via multiple threads since
- * it's synchronized properly.
- */
-class SimpleBlockingQueue implements BlockingQueue {
- /**
- * The queue consists of a List of E's.
- */
- final private List mList;
-
- /**
- * The maximum capacity of the queue or Integer.MAX_VALUE if none.
- */
- private final int mCapacity;
-
- /**
- * Create a SimpleBlocking queue with a capacity of
- * Integer.MAX_VALUE.
- */
- public SimpleBlockingQueue() {
- this(Integer.MAX_VALUE);
- }
-
- /**
- * Create a SimpleBlocking queue with the given capacity.
- */
- public SimpleBlockingQueue(int capacity) {
- if (capacity <= 0)
- throw new IllegalArgumentException();
- mCapacity = capacity;
- mList = new ArrayList();
- }
-
- /**
- * Add a new E to the end of the queue, blocking if necessary for
- * space to become available.
- */
- public void put(E e) throws InterruptedException {
- synchronized(this) {
- if (e == null)
- throw new NullPointerException();
-
- // Wait until the queue is not full.
- while (isFull()) {
- // System.out.println("BLOCKING ON PUT()");
- wait();
- }
-
- // Add e to the ArrayList.
- mList.add(e);
-
- // Notify that the queue may have changed state, e.g., "no
- // longer empty".
- notifyAll();
- }
- }
-
- /**
- * Remove the E at the front of the queue, blocking until there's
- * something in the queue.
- */
- public E take() throws InterruptedException {
- synchronized(this) {
- // Wait until the queue is not empty.
- while (mList.isEmpty()) {
- // System.out.println("BLOCKING ON TAKE()");
- wait();
- }
-
- final E e = mList.remove(0);
-
- // Notify that the queue may have changed state, e.g., "no
- // longer full".
- notifyAll();
- return e;
- }
- }
-
- /**
- * Returns the number of elements in this queue.
- */
- public int size() {
- synchronized(this) {
- return mList.size();
- }
- }
-
- /**
- * Returns true if the queue is empty, else false.
- */
- public boolean isEmpty() {
- synchronized(this) {
- return mList.size() == 0;
- }
- }
-
- /**
- * Returns true if the queue is full, else false. Since this
- * isn't a public method it assumes the monitor lock is held.
- */
- private boolean isFull() {
- return mList.size() == mCapacity;
- }
-
- /**
- * All these methods are inherited from the BlockingQueue
- * interface. They are defined as no-ops and their implementations
- * are left as an exercise to the reader.
- */
- public int drainTo(Collection super E> c) {
- return 0;
- }
- public int drainTo(Collection super E> c, int maxElements) {
- return 0;
- }
- public boolean contains(Object o) {
- return false;
- }
- public boolean remove(Object o) {
- return false;
- }
- public int remainingCapacity() {
- return 0;
- }
- public E poll() {
- return null;
- }
- public E poll(long timeout, TimeUnit unit) throws InterruptedException {
- return take();
- }
- public E peek() {
- return null;
- }
- public boolean offer(E e) {
- return false;
- }
- public boolean offer(E e, long timeout, TimeUnit unit) {
- try {
- put(e);
- }
- catch (InterruptedException ex) {
- // Just swallow this exception for this simple (buggy) test.
- }
- return true;
- }
- public boolean add(E e) {
- return false;
- }
- public E element() {
- return null;
- }
- public E remove() {
- return null;
- }
- public void clear() {
- }
- public boolean retainAll(Collection> collection) {
- return false;
- }
- public boolean removeAll(Collection> collection) {
- return false;
- }
- public boolean addAll(Collection extends E> collection) {
- return false;
- }
- public boolean containsAll(Collection> collection) {
- return false;
- }
- public Object[] toArray() {
- return null;
- }
- public T[] toArray(T[] array) {
- return null;
- }
- public Iterator iterator() {
- return null;
- }
-}
diff --git a/SimpleBlockingQueue/src/SimpleBlockingQueueTest.java b/SimpleBlockingQueue/src/SimpleBlockingQueueTest.java
deleted file mode 100644
index 854bdb583..000000000
--- a/SimpleBlockingQueue/src/SimpleBlockingQueueTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-import java.util.concurrent.*;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.List;
-
-/**
- * @class SimpleBlockingQueueTest
- *
- * @brief Test program for the SimpleBlockingQueue that induces race
- * conditions due to lack of synchronization.
- */
-public class SimpleBlockingQueueTest
-{
- /**
- * Maximum number of iterations.
- */
- private final static int mMaxIterations = 100000;
-
- /**
- * Maximum size of the queue.
- */
- private final static int mQueueSize = 10;
-
- /**
- * Count the number of iterations.
- */
- private final static AtomicInteger mCount =
- new AtomicInteger(0);
-
- /**
- * @class ProducerThread
- *
- * @brief This producer runs in a separate Java Thread and passes
- * Strings to a consumer Thread via a shared BlockingQueue.
- */
- static class ProducerThread extends Thread {
- /**
- * This queue is shared with the consumer.
- */
- private final BQ mQueue;
-
- /**
- * Constructor initializes the BlockingQueue data
- * member.
- */
- ProducerThread(BQ blockingQueue) {
- mQueue = blockingQueue;
- }
-
- /**
- * This method runs in a separate Java Thread and passes
- * Strings to a consumer Thread via a shared BlockingQueue.
- */
- public void run(){
- try {
- for(int i = 0; i < mMaxIterations; i++) {
- mCount.incrementAndGet();
-
- // Calls the put() method.
- mQueue.put(Integer.toString(i));
- }
- } catch (InterruptedException e) {
- System.out.println("InterruptedException caught");
- }
- }
- }
-
- /**
- * @class ConsumerThread
- *
- * @brief This consumer runs in a separate Java Thread and
- * receives Strings from a producer Thread via a shared
- * BlockingQueue.
- */
- static class ConsumerThread extends Thread {
- /**
- * This queue is shared with the producer.
- */
- private final BQ mQueue;
-
- /**
- * Constructor initializes the BlockingQueue data member.
- */
- ConsumerThread(BQ blockingQueue) {
- mQueue = blockingQueue;
- }
-
- /**
- * This method runs in a separate Java Thread and receives
- * Strings from a producer Thread via a shared BlockingQueue.
- */
- public void run(){
- Object s = null;
- try {
- for(int i = 0; i < mMaxIterations; i++) {
- // Calls the take() method.
- s = mQueue.take();
-
- mCount.decrementAndGet();
-
- if((i % (mMaxIterations / 10)) == 0)
- System.out.println(s);
- }
- } catch (InterruptedException e) {
- System.out.println("InterruptedException caught");
- }
- System.out.println("Final size of the queue is "
- + mQueue.size()
- + "\nmCount is "
- + mCount.get()
- + "\nFinal value is "
- + s);
- }
- }
-
- /**
- * Main entry point that tests the SimpleBlockingQueue class.
- */
- public static void main(String argv[]) {
- final SimpleBlockingQueue simpleQueue =
- new SimpleBlockingQueue(mQueueSize);
-
- try {
- // Create a ProducerThread.
- Thread producer =
- new ProducerThread(simpleQueue);
-
- // Create a ConsumerThread.
- Thread consumer =
- new ConsumerThread(simpleQueue);
-
- // Run both Threads concurrently.
- producer.start();
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {}
-
- consumer.start();
-
- // Wait for both Threads to stop.
- producer.join();
- consumer.join();
- } catch (Exception e) {
- System.out.println("caught exception");
- }
- }
-}
diff --git a/SimpleBlockingQueue/src/main/java/edu/vandy/BoundedQueue.java b/SimpleBlockingQueue/src/main/java/edu/vandy/BoundedQueue.java
new file mode 100644
index 000000000..c80a8109a
--- /dev/null
+++ b/SimpleBlockingQueue/src/main/java/edu/vandy/BoundedQueue.java
@@ -0,0 +1,76 @@
+package edu.vandy;
+
+/**
+ * Defines an interface for a bounded queue.
+ */
+public interface BoundedQueue {
+ /**
+ * Inserts the specified element into this queue, waiting if
+ * necessary for space to become available.
+ *
+ * @param e the element to add
+ * @throws InterruptedException if interrupted while waiting
+ */
+ default void put(E e)
+ throws InterruptedException {
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, waiting if necessary
+ * until an element becomes available.
+ *
+ * @return the head of this queue
+ * @throws InterruptedException if interrupted while waiting
+ */
+ default E take()
+ throws InterruptedException {
+ return null;
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, or returns {@code
+ * null} if this queue is empty.
+ *
+ * @return the head of this queue, or {@code null} if this queue is empty
+ */
+ default E poll() {
+ return null;
+ }
+
+ /**
+ * Inserts the specified element into this queue if it is possible to do
+ * so immediately without violating capacity restrictions, returning
+ * {@code true} upon success and {@code false} if no space is currently
+ * available.
+ *
+ * @return {@code true} if the element was added to this queue, else
+ * {@code false}
+ */
+ default boolean offer(E e) {
+ return false;
+ }
+
+ /**
+ * Returns true if this queue contains no elements, else false.
+ *
+ * @return true if this queue contains no elements, else false.
+ */
+ boolean isEmpty();
+
+ /**
+ * Returns true if this queue is full, else false.
+ *
+ * @return true if this queue is full, else false.
+ */
+ boolean isFull();
+
+ /**
+ * Returns the number of elements in this queue.
+ *
+ * @return the number of elements in this collection
+ */
+ int size();
+}
+
+
+
diff --git a/SimpleBlockingQueue/src/main/java/edu/vandy/SimpleBlockingBoundedQueue.java b/SimpleBlockingQueue/src/main/java/edu/vandy/SimpleBlockingBoundedQueue.java
new file mode 100644
index 000000000..df0299739
--- /dev/null
+++ b/SimpleBlockingQueue/src/main/java/edu/vandy/SimpleBlockingBoundedQueue.java
@@ -0,0 +1,126 @@
+package edu.vandy;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+
+/*
+ * Defines an implementation of the BoundedQueue interface that works
+ * properly when accessed via multiple threads since it's synchronized
+ * properly.
+ */
+class SimpleBlockingBoundedQueue
+ implements BoundedQueue {
+ /**
+ * The queue consists of a LinkedList of E's.
+ */
+ final private List mList;
+
+ /**
+ * The maximum capacity of the queue or Integer.MAX_VALUE if none.
+ */
+ private final int mCapacity;
+
+ /**
+ * Create a SimpleBlocking queue with a capacity of
+ * Integer.MAX_VALUE.
+ */
+ public SimpleBlockingBoundedQueue() {
+ this(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Create a SimpleBlocking queue with the given capacity.
+ */
+ public SimpleBlockingBoundedQueue(int capacity) {
+ if (capacity <= 0)
+ throw new IllegalArgumentException();
+ mCapacity = capacity;
+ mList = new LinkedList<>();
+ }
+
+ /**
+ * Inserts the specified element into this queue, waiting if
+ * necessary for space to become available.
+ *
+ * @param e the element to add
+ * @throws InterruptedException if interrupted while waiting
+ */
+ @Override
+ public void put(E e)
+ throws InterruptedException {
+ synchronized(this) {
+ if (e == null)
+ throw new NullPointerException();
+
+ // Wait until the queue is not full.
+ while (isFull()) {
+ // System.out.println("BLOCKING ON PUT()");
+ wait();
+ }
+
+ // Add e to the LinkedList.
+ mList.add(e);
+
+ // Notify that the queue may have changed state, e.g., "no
+ // longer empty".
+ notifyAll();
+ }
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, waiting if necessary
+ * until an element becomes available.
+ *
+ * @return the head of this queue
+ * @throws InterruptedException if interrupted while waiting
+ */
+ @Override
+ public E take() throws InterruptedException {
+ synchronized(this) {
+ // Wait until the queue is not empty.
+ while (mList.isEmpty()) {
+ // System.out.println("BLOCKING ON TAKE()");
+ wait();
+ }
+
+ final E e = mList.remove(0);
+
+ // Notify that the queue may have changed state, e.g., "no
+ // longer full".
+ notifyAll();
+ return e;
+ }
+ }
+
+ /**
+ * Returns true if the queue is empty, else false.
+ */
+ @Override
+ public boolean isEmpty() {
+ synchronized(this) {
+ return mList.size() == 0;
+ }
+ }
+
+ /**
+ * Returns true if the queue is full, else false. Since this
+ * isn't a public method it assumes the monitor lock is held.
+ */
+ @Override
+ public boolean isFull() {
+ return mList.size() == mCapacity;
+ }
+
+ /**
+ * Returns the number of elements in this queue.
+ */
+ @Override
+ public int size() {
+ synchronized(this) {
+ return mList.size();
+ }
+ }
+}
diff --git a/SimpleBlockingQueue/src/test/java/edu/vandy/SimpleBlockingBoundedQueueTest.java b/SimpleBlockingQueue/src/test/java/edu/vandy/SimpleBlockingBoundedQueueTest.java
new file mode 100644
index 000000000..7129f17d8
--- /dev/null
+++ b/SimpleBlockingQueue/src/test/java/edu/vandy/SimpleBlockingBoundedQueueTest.java
@@ -0,0 +1,158 @@
+package edu.vandy;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Test;
+
+/**
+ * Test program for the SimpleBlockingBoundedQueue that fixes race conditions
+ * by having proper synchronization (i.e., mutual exclusion and
+ * coordination).
+ */
+public class SimpleBlockingBoundedQueueTest {
+ /**
+ * Maximum number of iterations.
+ */
+ private final static int mMaxIterations = 100000;
+
+ /**
+ * Maximum size of the queue.
+ */
+ private final static int sQUEUE_SIZE = 10;
+
+ /**
+ * Count the number of iterations.
+ */
+ private final static AtomicInteger mCount =
+ new AtomicInteger(0);
+
+ /**
+ * This producer runs in a separate Java thread and passes integers
+ * to a consumer thread via a shared BoundedQueue.
+ */
+ private static class Producer>
+ implements Runnable {
+ /**
+ * This queue is shared with the consumer.
+ */
+ private final BQ mQueue;
+
+ /**
+ * Constructor initializes the BoundedQueue data
+ * member.
+ */
+ Producer(BQ blockingQueue) {
+ mQueue = blockingQueue;
+ }
+
+ /**
+ * This method runs in a separate Java thread and passes
+ * integers to a consumer thread via a shared BoundedQueue.
+ */
+ public void run(){
+ try {
+ for (int i = 0; i < mMaxIterations; i++) {
+ mCount.incrementAndGet();
+
+ // Call the put() method.
+ mQueue.put(i);
+ }
+ } catch (InterruptedException e) {
+ System.out.println("InterruptedException caught");
+ }
+ }
+ }
+
+ /**
+ * This consumer runs in a separate Java thread and receives
+ * integers from a producer thread via a shared BoundedQueue.
+ */
+ private static class Consumer>
+ implements Runnable {
+ /**
+ * This queue is shared with the producer.
+ */
+ private final BQ mQueue;
+
+ /**
+ * Constructor initializes the BoundedQueue data member.
+ */
+ Consumer(BQ blockingQueue) {
+ mQueue = blockingQueue;
+ }
+
+ /**
+ * This method runs in a separate Java thread and receives
+ * integers from a producer thread[q via a shared BoundedQueue.
+ */
+ public void run() {
+ Integer integer = null;
+
+ try {
+ // Get the first item from the queue.
+ Integer previous = mQueue.take();
+ mCount.decrementAndGet();
+
+ for (int i = 1; i < mMaxIterations; ++i) {
+ // Calls the take() method.
+ integer = mQueue.take();
+
+ // Make sure the entries are ordered.
+ assertEquals(previous + 1, integer.intValue());
+ previous = integer;
+
+ if((i % (mMaxIterations / 10)) == 0)
+ System.out.println(integer);
+
+ mCount.decrementAndGet();
+ }
+ } catch (InterruptedException e) {
+ System.out.println("InterruptedException caught");
+ }
+ assertEquals(0, mCount.get());
+
+ System.out.println("Final size of the queue is "
+ + mQueue.size()
+ + "\nmCount is "
+ + mCount.get()
+ + "\nFinal value is "
+ + integer);
+ }
+ }
+
+ /**
+ * Main entry point that tests the SimpleBoundedQueue class.
+ */
+ @Test
+ public void testSimpleBlockingBoundedQueue() {
+ final SimpleBlockingBoundedQueue simpleQueue =
+ new SimpleBlockingBoundedQueue<>(sQUEUE_SIZE);
+
+ try {
+ // Create producer and consumer threads.
+ Thread[] threads = new Thread[] {
+ new Thread(new Producer<>(simpleQueue)),
+ new Thread(new Consumer<>(simpleQueue))
+ };
+
+ // Record the start time.
+ long startTime = System.nanoTime();
+
+ // Start both threads.
+ for (Thread thread : threads)
+ thread.start();
+
+ // Wait for both threads to stop.
+ for (Thread thread : threads)
+ thread.join();
+
+ System.out.println("test ran in "
+ + (System.nanoTime() - startTime) / 1_000_000
+ + " msecs");
+ } catch (Exception e) {
+ System.out.println("caught exception");
+ }
+ }
+}