1 /*
   2  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package nsk.share.locks;
  24 
  25 /*
  26  *  Thread intended to hold given lock until method releaseLock() not called
  27  *
  28  *   Example of usage:
  29  *
  30  *   Object lockToHold = new Object();
  31  *   MonitorLockingThread lockingThread = new MonitorLockingThread(lockToHold);
  32  *
  33  *   // after calling this method lock 'lockToHold' is acquired by lockingThread
  34  *   lockingThread.acquireLock();
  35  *
  36  *   // after calling this method lockingThread releases 'lockToHold' and finishes execution
  37  *   lockingThread.releaseLock();
  38  */
  39 public class MonitorLockingThread extends Thread {
  40     /*
  41      *   Class MonitorLockingThread is written for usage in tests provoking monitor contention.
  42      *   Typically in these tests exists thread holding lock (MonitorLockingThread) and another
  43      *   thread trying to acquire the same lock. But this scenario also requires one more thread
  44      *   which will force MonitorLockingThread to release lock when contention occurred, for this purpose
  45      *   auxiliary thread class LockFreeThread is written.
  46      *
  47      *   Example of usage of MonitorLockingThread and LockFreeThread:
  48      *
  49      *   Object lock = new Object();
  50      *   MonitorLockingThread monitorLockingThread = new MonitorLockingThread(lock);
  51      *
  52      *   MonitorLockingThread.LockFreeThread lockFreeThread =
  53      *       new MonitorLockingThread.LockFreeThread(Thread.currentThread(), monitorLockingThread);
  54      *
  55      *   monitorLockingThread.acquireLock();
  56      *
  57      *   lockFreeThread.start();
  58      *
  59      *   // try to acquire lock which is already held by MonitorLockingThread (here monitor contention should occur),
  60      *   // when LockFreeThread finds that contention occurred it forces MonitorLockingThread to release lock
  61      *   // and current thread is able to continue execution
  62      *   synchronized (lock) {
  63      *   }
  64      */
  65     public static class LockFreeThread extends Thread {
  66         private Thread blockedThread;
  67 
  68         private MonitorLockingThread lockingThread;
  69 
  70         public LockFreeThread(Thread blockedThread, MonitorLockingThread lockingThread) {
  71             this.blockedThread = blockedThread;
  72             this.lockingThread = lockingThread;
  73         }
  74 
  75         public void run() {
  76             /*
  77              * Wait when blockedThread's state will switch to 'BLOCKED' (at that moment monitor contention
  78              * should already occur) and then force MonitorLockingThread to release lock
  79              */
  80             while (blockedThread.getState() != Thread.State.BLOCKED)
  81                 yield();
  82 
  83             lockingThread.releaseLock();
  84         }
  85     }
  86 
  87     private volatile boolean isRunning = true;
  88 
  89     private volatile boolean holdsLock;
  90 
  91     private Object lockToHold;
  92 
  93     public MonitorLockingThread(Object lockToHold) {
  94         this.lockToHold = lockToHold;
  95     }
  96 
  97     public void run() {
  98         synchronized (lockToHold) {
  99             holdsLock = true;
 100             while (isRunning)
 101                 yield();
 102         }
 103         holdsLock = false;
 104     }
 105 
 106     public void releaseLock() {
 107         isRunning = false;
 108         while (holdsLock)
 109             yield();
 110     }
 111 
 112     public void acquireLock() {
 113         start();
 114         while (!holdsLock)
 115             yield();
 116     }
 117 }