alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (SynchronizationStatistics.java)

This example Java source code file (SynchronizationStatistics.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

blockedthread, diff, examiner, expected, failed, interruptedexception, management, object, runtimeexception, semaphore, statthread, string, test, threadinfo, waited

The SynchronizationStatistics.java Java example source code

/*
 * Copyright (c) 2003, 2013, 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.
 */

/*
 * @test
 * @bug     4530538
 * @summary Basic unit test of the synchronization statistics support:
 *
 * @author  Mandy Chung
 *
 * @ignore  6309226
 * @build Semaphore
 * @run main/othervm SynchronizationStatistics
 */

import java.lang.management.*;

public class SynchronizationStatistics {
    private static ThreadMXBean mbean = ManagementFactory.getThreadMXBean();

    private static boolean blockedTimeCheck =
        mbean.isThreadContentionMonitoringSupported();
    private static boolean trace = false;

    private static Object lockA = new Object();
    private static Object lockB = new Object();
    private static Object lockC = new Object();
    private static Object lockD = new Object();
    private static Object waiter = new Object();
    private static volatile boolean testFailed = false;

    private static Object go = new Object();

    private static void goSleep(long ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Unexpected exception.");
            testFailed = true;
        }
    }

    public static void main(String args[]) throws Exception {
        if (args.length > 0 && args[0].equals("trace")) {
            trace = true;
        }

        if (blockedTimeCheck) {
            mbean.setThreadContentionMonitoringEnabled(true);
        }

        if (!mbean.isThreadContentionMonitoringEnabled()) {
            throw new RuntimeException("TEST FAILED: " +
                "Thread Contention Monitoring is not enabled");
        }

        Examiner examiner = new Examiner("Examiner");
        BlockedThread blocked = new BlockedThread("BlockedThread");
        examiner.setThread(blocked);

        // Start the threads and check them in  Blocked and Waiting states
        examiner.start();

        // wait until the examiner acquires all the locks and waiting
        // for the BlockedThread to start
        examiner.waitUntilWaiting();

        System.out.println("Checking the thread state for the examiner thread " +
                           "is waiting to begin.");

        // The Examiner should be waiting to be notified by the BlockedThread
        checkThreadState(examiner, Thread.State.WAITING);

        System.out.println("Now starting the blocked thread");
        blocked.start();

        try {
            examiner.join();
            blocked.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Unexpected exception.");
            testFailed = true;
        }

        if (testFailed)
            throw new RuntimeException("TEST FAILED.");

        System.out.println("Test passed.");
    }

    private static String INDENT = "    ";
    private static void printStack(Thread t, StackTraceElement[] stack) {
        System.out.println(INDENT +  t +
                           " stack: (length = " + stack.length + ")");
        if (t != null) {
            for (int j = 0; j < stack.length; j++) {
                System.out.println(INDENT + stack[j]);
            }
            System.out.println();
        }
    }

    private static void checkThreadState(Thread thread, Thread.State s)
        throws Exception {

        ThreadInfo ti = mbean.getThreadInfo(thread.getId());
        if (ti.getThreadState() != s) {
            ThreadInfo info = mbean.getThreadInfo(thread.getId(),
                                                  Integer.MAX_VALUE);
            System.out.println(INDENT + "TEST FAILED:");
            printStack(thread, info.getStackTrace());
            System.out.println(INDENT + "Thread state: " + info.getThreadState());

            throw new RuntimeException("TEST FAILED: " +
                "Thread state for " + thread + " returns " + ti.getThreadState() +
                ".  Expected to be " + s);
        }
    }

    private static void checkThreadState(Thread thread,
                                         Thread.State s1, Thread.State s2)
        throws Exception {

        ThreadInfo ti = mbean.getThreadInfo(thread.getId());
        if (ti.getThreadState() != s1 && ti.getThreadState() != s2) {
            throw new RuntimeException("TEST FAILED: " +
                "Thread state for " + thread + " returns " + ti.getThreadState() +
                ".  Expected to be " + s1 + " or " + s2);
        }
    }

    static class StatThread extends Thread {
        private long blockingBaseTime = 0;
        private long totalWaitTime = 0;
        private long totalBlockedEnterTime = 0;

        StatThread(String name) {
            super(name);
        }

        void addWaitTime(long ns) {
            totalWaitTime = totalWaitTime + ns;
        }
        void addBlockedEnterTime(long ns) {
            totalBlockedEnterTime = totalBlockedEnterTime + ns;
        }
        void setBlockingBaseTime(long time) {
            blockingBaseTime = time;
        }

        long totalBlockedTimeMs() {
            return totalBlockedEnterTime / 1000000;
        }

        long totalBlockedTimeMs(long now) {
            long t = totalBlockedEnterTime + (now - blockingBaseTime);
            return t / 1000000;
        }

        long totalWaitTimeMs() {
            return totalWaitTime / 1000000;
        }

        long totalWaitTimeMs(long now) {
            long t = totalWaitTime + (now - blockingBaseTime);
            return t / 1000000;
        }
    }

    static class BlockedThread extends StatThread {
        private Semaphore handshake = new Semaphore();
        BlockedThread(String name) {
            super(name);
        }
        void waitUntilBlocked() {
            handshake.semaP();

            // give a chance for the examiner thread to really wait
            goSleep(20);
        }

        void waitUntilWaiting() {
            waitUntilBlocked();
        }

        boolean hasWaitersForBlocked() {
            return (handshake.getWaiterCount() > 0);
        }

        private void notifyWaiter() {
            // wait until the examiner waits on the semaphore
            while (handshake.getWaiterCount() == 0) {
                goSleep(20);
            }
            handshake.semaV();
        }

        private void waitObj(long ms) {
            synchronized (waiter) {
                try {
                    // notify examinerabout to wait on a monitor
                    notifyWaiter();

                    long base = System.nanoTime();
                    setBlockingBaseTime(base);
                    waiter.wait(ms);
                    long now = System.nanoTime();
                    addWaitTime(now - base);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("Unexpected exception.");
                    testFailed = true;
                }
            }
        }

        private void test() {
            // notify examiner about to block on lockA
            notifyWaiter();

            long base = System.nanoTime();
            setBlockingBaseTime(base);
            synchronized (lockA) {
                long now = System.nanoTime();
                addBlockedEnterTime(now - base);

                A(); // Expected blocked count = 1
            }
            E();
        }
        private void A() {
            // notify examiner about to block on lockB
            notifyWaiter();

            long base = System.nanoTime();
            setBlockingBaseTime(base);
            synchronized (lockB) {
                long now = System.nanoTime();
                addBlockedEnterTime(now - base);

                B(); // Expected blocked count = 2
            }
        }
        private void B() {
            // notify examiner about to block on lockC
            notifyWaiter();

            long base = System.nanoTime();
            setBlockingBaseTime(base);
            synchronized (lockC) {
                long now = System.nanoTime();
                addBlockedEnterTime(now - base);

                C();  // Expected blocked count = 3
            }
        }
        private void C() {
            // notify examiner about to block on lockD
            notifyWaiter();

            long base = System.nanoTime();
            setBlockingBaseTime(base);
            synchronized (lockD) {
                long now = System.nanoTime();
                addBlockedEnterTime(now - base);

                D();  // Expected blocked count = 4
            }
        }
        private void D() {
            goSleep(50);
        }
        private void E() {
            final int WAIT = 1000;
            waitObj(WAIT);
            waitObj(WAIT);
            waitObj(WAIT);
        }

        public void run() {
            test();
        } // run()
    } // BlockedThread

    static int blockedCount = 0;
    static int waitedCount = 0;
    static class Examiner extends StatThread {
        private BlockedThread blockedThread;
        private Semaphore semaphore = new Semaphore();

        Examiner(String name) {
            super(name);
        }

        public void setThread(BlockedThread thread) {
            blockedThread = thread;
        }

        private void blockedTimeRangeCheck(StatThread t,
                                           long blockedTime,
                                           long nowNano)
            throws Exception {
            long expected = t.totalBlockedTimeMs(nowNano);

            // accept 5% range
            timeRangeCheck(blockedTime, expected, 5);
        }
        private void waitedTimeRangeCheck(StatThread t,
                                          long waitedTime,
                                          long nowNano)
            throws Exception {
            long expected = t.totalWaitTimeMs(nowNano);

            // accept 5% range
            timeRangeCheck(waitedTime, expected, 5);
        }

        private void timeRangeCheck(long time, long expected, int percent)
            throws Exception {

            double diff = expected - time;

            if (trace) {
                 System.out.println("  Time = " + time +
                    " expected = " + expected +
                    ".  Diff = " + diff);

            }
            // throw an exception if blockedTime and expectedTime
            // differs > percent%
            if (diff < 0) {
                diff = diff * -1;
            }

            long range = (expected * percent) / 100;
            // minimum range = 2 ms
            if (range < 2) {
                range = 2;
            }
            if (diff > range) {
                throw new RuntimeException("TEST FAILED: " +
                    "Time returned = " + time +
                    " expected = " + expected + ".  Diff = " + diff);
            }
        }
        private void checkInfo(StatThread t, Thread.State s, Object lock,
                               String lockName, int bcount, int wcount)
            throws Exception {

            String action = "ERROR";
            if (s == Thread.State.WAITING || s == Thread.State.TIMED_WAITING) {
                action = "wait on ";
            } else if (s == Thread.State.BLOCKED) {
                action = "block on ";
            }
            System.out.println(t + " expected to " + action + lockName +
                " with blocked count = " + bcount +
                " and waited count = " + wcount);

            long now = System.nanoTime();
            ThreadInfo info = mbean.getThreadInfo(t.getId());
            if (info.getThreadState() != s) {
                printStack(t, info.getStackTrace());
                throw new RuntimeException("TEST FAILED: " +
                    "Thread state returned is " + info.getThreadState() +
                    ". Expected to be " + s);
            }

            if (info.getLockName() == null ||
                !info.getLockName().equals(lock.toString())) {
                throw new RuntimeException("TEST FAILED: " +
                    "getLockName() returned " + info.getLockName() +
                    ". Expected to be " + lockName + " - "  + lock.toString());
            }

            if (info.getBlockedCount() != bcount) {
                throw new RuntimeException("TEST FAILED: " +
                    "Blocked Count returned is " + info.getBlockedCount() +
                    ". Expected to be " + bcount);
            }
            if (info.getWaitedCount() != wcount) {
                throw new RuntimeException("TEST FAILED: " +
                    "Waited Count returned is " + info.getWaitedCount() +
                    ". Expected to be " + wcount);
            }

            String lockObj = info.getLockName();
            if (lockObj == null || !lockObj.equals(lock.toString())) {
                throw new RuntimeException("TEST FAILED: " +
                    "Object blocked on is " + lockObj  +
                    ". Expected to be " + lock.toString());
            }

            if (!blockedTimeCheck) {
                return;
            }
            long blockedTime = info.getBlockedTime();
            if (blockedTime < 0) {
                throw new RuntimeException("TEST FAILED: " +
                    "Blocked time returned is negative = " + blockedTime);
            }

            if (s == Thread.State.BLOCKED) {
                blockedTimeRangeCheck(t, blockedTime, now);
            } else {
                timeRangeCheck(blockedTime, t.totalBlockedTimeMs(), 5);
            }

            long waitedTime = info.getWaitedTime();
            if (waitedTime < 0) {
                throw new RuntimeException("TEST FAILED: " +
                    "Waited time returned is negative = " + waitedTime);
            }
            if (s == Thread.State.WAITING || s == Thread.State.TIMED_WAITING) {
                waitedTimeRangeCheck(t, waitedTime, now);
            } else {
                timeRangeCheck(waitedTime, t.totalWaitTimeMs(), 5);
            }

        }

        private void examine() {
            try {
                synchronized (lockD) {
                    synchronized (lockC) {
                        synchronized (lockB) {
                            synchronized (lockA) {
                                // notify main thread to continue
                                semaphore.semaV();

                                // wait until BlockedThread has started
                                blockedThread.waitUntilBlocked();

                                blockedCount++;
                                checkInfo(blockedThread, Thread.State.BLOCKED,
                                          lockA, "lockA",
                                          blockedCount, waitedCount);
                            }

                           // wait until BlockedThread to block on lockB
                            blockedThread.waitUntilBlocked();

                            blockedCount++;
                            checkInfo(blockedThread, Thread.State.BLOCKED,
                                      lockB, "lockB",
                                      blockedCount, waitedCount);
                        }

                        // wait until BlockedThread to block on lockC
                        blockedThread.waitUntilBlocked();

                        blockedCount++;
                        checkInfo(blockedThread, Thread.State.BLOCKED,
                                  lockC, "lockC",
                                  blockedCount, waitedCount);
                    }
                    // wait until BlockedThread to block on lockD
                    blockedThread.waitUntilBlocked();
                    blockedCount++;

                    checkInfo(blockedThread, Thread.State.BLOCKED,
                              lockD, "lockD",
                              blockedCount, waitedCount);
                }

                // wait until BlockedThread about to call E()
                // BlockedThread will wait on waiter for 3 times
                blockedThread.waitUntilWaiting();

                waitedCount++;
                checkInfo(blockedThread, Thread.State.TIMED_WAITING,
                          waiter, "waiter", blockedCount, waitedCount);

                blockedThread.waitUntilWaiting();

                waitedCount++;
                checkInfo(blockedThread, Thread.State.TIMED_WAITING,
                          waiter, "waiter", blockedCount, waitedCount);

                blockedThread.waitUntilWaiting();

                waitedCount++;
                checkInfo(blockedThread, Thread.State.TIMED_WAITING,
                          waiter, "waiter", blockedCount, waitedCount);

            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("Unexpected exception.");
                testFailed = true;
            }
        }

        public void run() {
            examine();
        } // run()

        public void waitUntilWaiting() {
            semaphore.semaP();

            // wait until the examiner is waiting for
            while (!blockedThread.hasWaitersForBlocked()) {
                goSleep(50);
            }
            // give a chance for the examiner thread to really wait
            goSleep(20);

        }
    } // Examiner
}

Other Java examples (source code examples)

Here is a short list of links related to this Java SynchronizationStatistics.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.