/* * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * * Sample target application for jvmti demos * * java Context [threadCount [iterationCount [sleepContention]]] * Default: java Context 5 10 0 * * threadCount Number of threads * iterationCount Total turns taken for all threads * sleepContention Time for main thread to sleep while holding lock * (creates monitor contention on all other threads) * */ /* Used to sync up turns and keep track of who's turn it is */ final class TurnChecker { int thread_index; TurnChecker(int thread_index) { this.thread_index = thread_index; } } /* Creates a bunch of threads that sequentially take turns */ public final class Context extends Thread { /* Used to track threads */ private static long startTime; private static TurnChecker turn = new TurnChecker(-1); private static int total_turns_taken; /* Used for each Context thread */ private final int thread_count; private final int thread_index; private final int thread_turns; /* Main program */ public static void main(String[] argv) throws InterruptedException { int default_thread_count = 5; int default_thread_turns = 10; int default_contention_sleep = 0; int expected_turns_taken; long sleepTime = 10L; /* Override defaults */ if ( argv.length >= 1 ) { default_thread_count = Integer.parseInt(argv[0]); } if ( argv.length >= 2 ) { expected_turns_taken = Integer.parseInt(argv[1]); default_thread_turns = expected_turns_taken/default_thread_count; } expected_turns_taken = default_thread_count*default_thread_turns; if ( argv.length >= 3 ) { default_contention_sleep = Integer.parseInt(argv[2]); } System.out.println("Context started with " + default_thread_count + " threads and " + default_thread_turns + " turns per thread"); /* Get all threads running (they will block until we set turn) */ for (int i = 0; i < default_thread_count; i++) { new Context(default_thread_count, i, default_thread_turns).start(); } /* Sleep to make sure thread_index 0 make it to the wait call */ System.out.println("Context sleeping, so threads will start wait"); Thread.yield(); Thread.sleep(sleepTime); /* Save start time */ startTime = System.currentTimeMillis(); /* This triggers the starting of taking turns */ synchronized (turn) { turn.thread_index = 0; turn.notifyAll(); } System.out.println("Context sleeping, so threads can run"); Thread.yield(); Thread.sleep(sleepTime); /* Wait for threads to finish (after everyone has had their turns) */ while ( true ) { boolean done; done = false; synchronized (turn) { if ( total_turns_taken == expected_turns_taken ) { done = true; } /* Create some monitor contention by sleeping with lock */ if ( default_contention_sleep > 0 ) { System.out.println("Context sleeping, to create contention"); Thread.yield(); Thread.sleep((long)default_contention_sleep); } } if ( done ) break; System.out.println("Context sleeping, so threads will complete"); Thread.sleep(sleepTime); } long endTime = System.currentTimeMillis(); long totalTime = endTime - startTime; System.out.println("Total time (milliseconds): " + totalTime); System.out.println("Milliseconds per thread: " + ((double)totalTime / (default_thread_count))); System.out.println("Context completed"); System.exit(0); } /* Thread object to run */ Context(int thread_count, int thread_index, int thread_turns) { this.thread_count = thread_count; this.thread_index = thread_index; this.thread_turns = thread_turns; } /* Main for thread */ public void run() { int next_thread_index = (thread_index + 1) % thread_count; int turns_taken = 0; try { /* Loop until we make sure we get all our turns */ for (int i = 0; i < thread_turns * thread_count; i++) { synchronized (turn) { /* Keep waiting for our turn */ while (turn.thread_index != thread_index) turn.wait(); /* MY TURN! Each thread gets thread_turns */ total_turns_taken++; turns_taken++; System.out.println("Turn #" + total_turns_taken + " taken by thread " + thread_index + ", " + turns_taken + " turns taken by this thread"); /* Give next thread a turn */ turn.thread_index = next_thread_index; turn.notifyAll(); } /* If we've had all our turns, break out of this loop */ if (thread_turns == turns_taken) { System.out.println("Loop end: thread got " + turns_taken + " turns, expected " + thread_turns); break; } } } catch (InterruptedException intEx) { System.out.println("Got an InterruptedException:" + intEx); /* skip */ } /* Make sure we got all our turns */ if ( thread_turns != turns_taken ) { System.out.println("ERROR: thread got " + turns_taken + " turns, expected " + thread_turns); System.exit(1); } } }