import java.util.*; import java.util.concurrent.*; public class BlockingQueueTester { private static final int NUM_THREADS_DEFAULT = 20000; public static void assertTest(boolean test, String errorMessage, int pointsSoFar) { assert test : errorMessage + " Total Points: " + pointsSoFar; if (!test) { System.out.println("ERROR: " + errorMessage); } } public static void main(String[] args) { //System.out.println(); int numThreads = NUM_THREADS_DEFAULT; if (args.length > 0) { try { int inputThreads = Integer.parseInt(args[0]); if (inputThreads > 0) { numThreads = inputThreads; System.out.println("Setting numThreads to " + numThreads + "..."); } } catch (Exception e) { e.printStackTrace(); } } else { System.out.println("Using the default number of threads: " + numThreads + "."); } int expectedPoints = 0; MyBlockingQueue<String> strings = new MyBlockingQueue<>(10); MyBlockingQueue<Integer> ints = new MyBlockingQueue<>(13); MyBlockingQueue<String> tiny = new MyBlockingQueue<>(1); tiny.add("Hi"); ints.add(1337); //System.out.println(tiny); //System.out.println(ints); System.out.println("Testing toString..."); assertTest(tiny.toString().contains("Hi"), "I don't see the added element in the toString!", expectedPoints); assertTest(!strings.toString().contains("Hi"), "Why does the toString include the string 'Hi'? It shouldn't.", expectedPoints); assertTest(ints.toString().contains("1337"), "I don't see the added element in the toString!", expectedPoints); //finished toString expectedPoints += 10; System.out.println("Testing remove..."); //test remove basics int lastInt = ints.remove(); assertTest(lastInt == 1337, "Remove doesn't return the correct element on a queue of integers.", expectedPoints); assertTest(!ints.toString().contains("1337"), "It doesn't look like remove removes the element from the queue!", expectedPoints); String lastString = tiny.remove(); assertTest(lastString.equals("Hi"), "Remove doesn't return the correct element on a queue of Strings.", expectedPoints); strings.add("1"); strings.add("2"); lastString = strings.remove(); assertTest(lastString.equals("1"), "Remove doesn't return the correct element on a queue of Strings.", expectedPoints); //finished testing remove expectedPoints += 50; System.out.println("Testing getNumElements..."); //testing getNumElements //reset the queues while (ints.getNumElements() > 0) { ints.remove(); } while (tiny.getNumElements() > 0) { tiny.remove(); } while (strings.getNumElements() > 0) { strings.remove(); } assertTest(ints.getNumElements() == 0, "getNumElements doesn't work on an empty list.", expectedPoints); tiny.add("Hello"); assertTest(tiny.getNumElements() == 1, "getNumElements doesn't work on a list with one element.", expectedPoints); strings.add("mankey"); strings.add("primeape"); assertTest(strings.getNumElements() == 2, "getNumElements doesn't seem to work on a list with two elements.", expectedPoints); for (int i = 0; i < 13; i++) { ints.add(i); assertTest(ints.getNumElements() == (i+1), "getNumElements isn't working when there are " + i + " elements.", expectedPoints); } //finished testing getNumElements expectedPoints += 7; System.out.println("Testing getFreeSpace..."); //testing getFreeSpace //reset the queues while (ints.getNumElements() > 0) { ints.remove(); } while (tiny.getNumElements() > 0) { tiny.remove(); } while (strings.getNumElements() > 0) { strings.remove(); } assertTest(ints.getFreeSpace() == 13, "getFreeSpace doesn't work on an empty list.", expectedPoints); tiny.add("Hello"); assertTest(tiny.getFreeSpace() == 0, "getFreeSpace doesn't work on a list with one element.", expectedPoints); strings.add("mankey"); strings.add("primeape"); assertTest(strings.getFreeSpace() == 8, "getFreeSpace doesn't seem to work on a list with two elements.", expectedPoints); for (int i = 0; i < 13; i++) { ints.add(i); assertTest(ints.getFreeSpace() == (13 - i - 1), "getFreeSpace isn't working when there are " + i + " elements.", expectedPoints); } //finished testing getFreeSpace expectedPoints += 8; System.out.println("Testing FIFO-ness..."); //testing FIFO-ness //reset the queues while (ints.getNumElements() > 0) { ints.remove(); } while (tiny.getNumElements() > 0) { tiny.remove(); } while (strings.getNumElements() > 0) { strings.remove(); } for (int i = 0; i < 13; i++) { ints.add(i); } for (int i = 0; i < 13; i++) { assertTest(ints.remove() == i, "The queue doesn't maintain the FIFO-policy.", expectedPoints); } ints.add(5); ints.add(7); ints.add(9); assertTest(ints.remove() == 5, "The queue doesn't maintain the FIFO-policy.", expectedPoints); ints.add(11); ints.add(13); assertTest(ints.remove() == 7, "The queue doesn't maintain the FIFO-policy.", expectedPoints); assertTest(ints.remove() == 9, "The queue doesn't maintain the FIFO-policy.", expectedPoints); assertTest(ints.remove() == 11, "The queue doesn't maintain the FIFO-policy.", expectedPoints); assertTest(ints.remove() == 13, "The queue doesn't maintain the FIFO-policy.", expectedPoints); //finished testing fifo-ness expectedPoints += 10; System.out.println("Testing that remove() blocks correctly..."); //testing that remove blocks appropriately. //reset the queues while (ints.getNumElements() > 0) { ints.remove(); } while (tiny.getNumElements() > 0) { tiny.remove(); } while (strings.getNumElements() > 0) { strings.remove(); } Queue<String> flags = new ConcurrentLinkedQueue<>(); flags.add("Monkey"); Thread t = new Thread(() -> {ints.remove(); flags.add("Gibbon");}); t.start(); try { Thread.sleep(1000); } catch (Exception e) { //do nothing } assertTest(flags.size() == 1, "Remove doesn't block correctly.", expectedPoints); ints.add(1); try { Thread.sleep(100); } catch (Exception e) { //do nothing } flags.remove(); //remove Gibbon System.out.println("Testing multiple threads..."); for (int i = 0; i < 10; i++) { t = new Thread(() -> {int k = ints.remove(); flags.add("" + k); }); t.start(); } for (int i = 0; i < 10; i++) { try { Thread.sleep(200); } catch (Exception e) { //do nothing } assertTest(flags.size() == 1, "Remove doesn't block correctly! i=" + i + " ints: " + ints + " flags: " + flags, expectedPoints); ints.add(i); try { Thread.sleep(100); } catch (Exception e) { //do nothing } //System.out.println(flags.get(1)); flags.remove(); } //finished testing remove blocking expectedPoints += 30; System.out.println("Testing that add blocks correctly..."); //testing that add blocks appropriately. //reset the queues while (ints.getNumElements() > 0) { ints.remove(); } while (tiny.getNumElements() > 0) { tiny.remove(); } while (strings.getNumElements() > 0) { strings.remove(); } tiny.add("Monkey"); t = new Thread(() -> {tiny.add("Gibbon"); flags.add("Gibbon"); }); t.start(); try { Thread.sleep(100); } catch (Exception e) { //do nothing } assertTest(flags.size() == 1, "add() doesn't block correctly!", expectedPoints); tiny.remove(); try { Thread.sleep(100); } catch (Exception e) { //do nothing } flags.remove(); System.out.println("Testing multiple threads..."); //now test a bunch... for (int i = 0; i < 13; i++) { t = new Thread(() -> {tiny.add("Another Gibbon"); flags.add("Another Gibbon"); }); t.start(); } for (int i = 0; i < 13; i++) { try { Thread.sleep(100); } catch (Exception e) { //do nothing } assertTest(flags.size() == 1, "add() isn't blocking correctly!", expectedPoints); tiny.remove(); try { Thread.sleep(100); } catch (Exception e) { //do nothing } flags.remove(); } //done testing add expectedPoints += 30; System.out.println("Running the stress test..."); //now the stress test //reset the queues while (ints.getNumElements() > 0) { ints.remove(); } while (tiny.getNumElements() > 0) { tiny.remove(); } while (strings.getNumElements() > 0) { strings.remove(); } final long startTime = System.currentTimeMillis(); Queue<Thread> addingThreads = new ConcurrentLinkedQueue<>(); for (int i = 0; i < numThreads; i++) { int j = i; t = new Thread(() -> { ints.add(j); //System.out.println("j: " + j); }); t.start(); addingThreads.add(t); } System.out.println("Adding threads launched!"); Queue<Integer> completedThreads = new ConcurrentLinkedQueue<>(); Queue<Thread> threads = new ConcurrentLinkedQueue<>(); for (int i = 0; i < numThreads - 13; i++) { t = new Thread(() -> { //System.out.println(ints); int id = ints.remove(); completedThreads.add(id); //System.out.println("Adding id: " + id); }); threads.add(t); } System.out.println("Removing threads created!"); for (Thread thread : threads) { thread.start(); } System.out.println("Removing threads launched!"); for (Thread x : addingThreads) { try { x.join(); } catch (Exception e) { //do nothing } //addingThreads.remove(0); } System.out.println("Adding threads finished!"); for (Thread x : threads) { try { x.join(); } catch (Exception e) { //do nothing } //threads.remove(0); } System.out.println("Removing threads finished!"); Queue<Integer> alreadySeenIds = new ConcurrentLinkedQueue<>(); Queue<Integer> doublySeenIds = new ConcurrentLinkedQueue<>(); int k = 0; for (int id : completedThreads) { //completedThreads.toString(); //int id = completedThreads.get(k); if (k % 10 == 0) { //System.out.println(k + "-th completed id: " + id); } if (alreadySeenIds.contains(id)) { doublySeenIds.add(id); } k++; } assertTest(doublySeenIds.size() == 0, "Two threads pulled the same integers (" + doublySeenIds + ") out of the BlockingQueue! That shouldn't happen!", expectedPoints); //done with the stress test expectedPoints += 10; System.out.println("Stress test complete!"); final long endTime = System.currentTimeMillis(); long elapsed = endTime - startTime; int targetMillis = 16000 * numThreads / NUM_THREADS_DEFAULT; /* System.out.println("That took: " + elapsed + " milliseconds."); System.out.println("Target time: " + targetMillis + " milliseconds. (Based on your number of threads.)"); System.out.println( elapsed <= targetMillis ? "You got it in the target time, great!" : "That took a long time!"); */ /* int[][] targets = new int[][] {{10000, 20}, {13000, 15}, {16000, 10}, {20000, 5}}; int bonusPoints = 0; for (int i = 0; i < targets.length; i++) { int targetTime = targets[i][0] * numThreads / NUM_THREADS_DEFAULT; int bonus = targets[i][1]; if (elapsed <= targetTime) { bonusPoints = bonus; System.out.println("Your code seems to be fast enough for a bonus! (" + bonus + ") I would check with Kyle to make sure it runs fast enough on his machine."); break; } } expectedPoints += bonusPoints; */ try { assert false; } catch (Error e) { System.out.println("Just based on these tests, it looks like you'll earn " + expectedPoints + " points available. (I will also have to look at your code to check the other parts that can't be tested!)"); } } } //end of BlockingQueueTester.java