Thu, 31 Aug 2017 18:10:36 +0800
merge
aoqi@0 | 1 | /* |
aoqi@0 | 2 | * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved. |
aoqi@0 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
aoqi@0 | 4 | * |
aoqi@0 | 5 | * This code is free software; you can redistribute it and/or modify it |
aoqi@0 | 6 | * under the terms of the GNU General Public License version 2 only, as |
aoqi@0 | 7 | * published by the Free Software Foundation. Oracle designates this |
aoqi@0 | 8 | * particular file as subject to the "Classpath" exception as provided |
aoqi@0 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
aoqi@0 | 10 | * |
aoqi@0 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
aoqi@0 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
aoqi@0 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
aoqi@0 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
aoqi@0 | 15 | * accompanied this code). |
aoqi@0 | 16 | * |
aoqi@0 | 17 | * You should have received a copy of the GNU General Public License version |
aoqi@0 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
aoqi@0 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
aoqi@0 | 20 | * |
aoqi@0 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
aoqi@0 | 22 | * or visit www.oracle.com if you need additional information or have any |
aoqi@0 | 23 | * questions. |
aoqi@0 | 24 | */ |
aoqi@0 | 25 | |
aoqi@0 | 26 | /* |
aoqi@0 | 27 | File: Mutex.java |
aoqi@0 | 28 | |
aoqi@0 | 29 | Originally written by Doug Lea and released into the public domain. |
aoqi@0 | 30 | This may be used for any purposes whatsoever without acknowledgment. |
aoqi@0 | 31 | Thanks for the assistance and support of Sun Microsystems Labs, |
aoqi@0 | 32 | and everyone contributing, testing, and using this code. |
aoqi@0 | 33 | |
aoqi@0 | 34 | History: |
aoqi@0 | 35 | Date Who What |
aoqi@0 | 36 | 11Jun1998 dl Create public version |
aoqi@0 | 37 | */ |
aoqi@0 | 38 | |
aoqi@0 | 39 | package com.sun.corba.se.impl.orbutil.concurrent; |
aoqi@0 | 40 | |
aoqi@0 | 41 | /** |
aoqi@0 | 42 | * A simple non-reentrant mutual exclusion lock. |
aoqi@0 | 43 | * The lock is free upon construction. Each acquire gets the |
aoqi@0 | 44 | * lock, and each release frees it. Releasing a lock that |
aoqi@0 | 45 | * is already free has no effect. |
aoqi@0 | 46 | * <p> |
aoqi@0 | 47 | * This implementation makes no attempt to provide any fairness |
aoqi@0 | 48 | * or ordering guarantees. If you need them, consider using one of |
aoqi@0 | 49 | * the Semaphore implementations as a locking mechanism. |
aoqi@0 | 50 | * <p> |
aoqi@0 | 51 | * <b>Sample usage</b><br> |
aoqi@0 | 52 | * <p> |
aoqi@0 | 53 | * Mutex can be useful in constructions that cannot be |
aoqi@0 | 54 | * expressed using java synchronized blocks because the |
aoqi@0 | 55 | * acquire/release pairs do not occur in the same method or |
aoqi@0 | 56 | * code block. For example, you can use them for hand-over-hand |
aoqi@0 | 57 | * locking across the nodes of a linked list. This allows |
aoqi@0 | 58 | * extremely fine-grained locking, and so increases |
aoqi@0 | 59 | * potential concurrency, at the cost of additional complexity and |
aoqi@0 | 60 | * overhead that would normally make this worthwhile only in cases of |
aoqi@0 | 61 | * extreme contention. |
aoqi@0 | 62 | * <pre> |
aoqi@0 | 63 | * class Node { |
aoqi@0 | 64 | * Object item; |
aoqi@0 | 65 | * Node next; |
aoqi@0 | 66 | * Mutex lock = new Mutex(); // each node keeps its own lock |
aoqi@0 | 67 | * |
aoqi@0 | 68 | * Node(Object x, Node n) { item = x; next = n; } |
aoqi@0 | 69 | * } |
aoqi@0 | 70 | * |
aoqi@0 | 71 | * class List { |
aoqi@0 | 72 | * protected Node head; // pointer to first node of list |
aoqi@0 | 73 | * |
aoqi@0 | 74 | * // Use plain java synchronization to protect head field. |
aoqi@0 | 75 | * // (We could instead use a Mutex here too but there is no |
aoqi@0 | 76 | * // reason to do so.) |
aoqi@0 | 77 | * protected synchronized Node getHead() { return head; } |
aoqi@0 | 78 | * |
aoqi@0 | 79 | * boolean search(Object x) throws InterruptedException { |
aoqi@0 | 80 | * Node p = getHead(); |
aoqi@0 | 81 | * if (p == null) return false; |
aoqi@0 | 82 | * |
aoqi@0 | 83 | * // (This could be made more compact, but for clarity of illustration, |
aoqi@0 | 84 | * // all of the cases that can arise are handled separately.) |
aoqi@0 | 85 | * |
aoqi@0 | 86 | * p.lock.acquire(); // Prime loop by acquiring first lock. |
aoqi@0 | 87 | * // (If the acquire fails due to |
aoqi@0 | 88 | * // interrupt, the method will throw |
aoqi@0 | 89 | * // InterruptedException now, |
aoqi@0 | 90 | * // so there is no need for any |
aoqi@0 | 91 | * // further cleanup.) |
aoqi@0 | 92 | * for (;;) { |
aoqi@0 | 93 | * if (x.equals(p.item)) { |
aoqi@0 | 94 | * p.lock.release(); // release current before return |
aoqi@0 | 95 | * return true; |
aoqi@0 | 96 | * } |
aoqi@0 | 97 | * else { |
aoqi@0 | 98 | * Node nextp = p.next; |
aoqi@0 | 99 | * if (nextp == null) { |
aoqi@0 | 100 | * p.lock.release(); // release final lock that was held |
aoqi@0 | 101 | * return false; |
aoqi@0 | 102 | * } |
aoqi@0 | 103 | * else { |
aoqi@0 | 104 | * try { |
aoqi@0 | 105 | * nextp.lock.acquire(); // get next lock before releasing current |
aoqi@0 | 106 | * } |
aoqi@0 | 107 | * catch (InterruptedException ex) { |
aoqi@0 | 108 | * p.lock.release(); // also release current if acquire fails |
aoqi@0 | 109 | * throw ex; |
aoqi@0 | 110 | * } |
aoqi@0 | 111 | * p.lock.release(); // release old lock now that new one held |
aoqi@0 | 112 | * p = nextp; |
aoqi@0 | 113 | * } |
aoqi@0 | 114 | * } |
aoqi@0 | 115 | * } |
aoqi@0 | 116 | * } |
aoqi@0 | 117 | * |
aoqi@0 | 118 | * synchronized void add(Object x) { // simple prepend |
aoqi@0 | 119 | * // The use of `synchronized' here protects only head field. |
aoqi@0 | 120 | * // The method does not need to wait out other traversers |
aoqi@0 | 121 | * // who have already made it past head. |
aoqi@0 | 122 | * |
aoqi@0 | 123 | * head = new Node(x, head); |
aoqi@0 | 124 | * } |
aoqi@0 | 125 | * |
aoqi@0 | 126 | * // ... other similar traversal and update methods ... |
aoqi@0 | 127 | * } |
aoqi@0 | 128 | * </pre> |
aoqi@0 | 129 | * <p> |
aoqi@0 | 130 | * <p>This version adds some debugging capability: it will detect an attempt by a thread |
aoqi@0 | 131 | * that holds the lock to acquire it for a second time, and also an attempt by a thread that |
aoqi@0 | 132 | * does not hold the mutex to release it. |
aoqi@0 | 133 | * @see Semaphore |
aoqi@0 | 134 | * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] |
aoqi@0 | 135 | **/ |
aoqi@0 | 136 | |
aoqi@0 | 137 | import org.omg.CORBA.INTERNAL ; |
aoqi@0 | 138 | |
aoqi@0 | 139 | public class DebugMutex implements Sync { |
aoqi@0 | 140 | |
aoqi@0 | 141 | /** The lock status **/ |
aoqi@0 | 142 | protected boolean inuse_ = false; |
aoqi@0 | 143 | protected Thread holder_ = null; |
aoqi@0 | 144 | |
aoqi@0 | 145 | public void acquire() throws InterruptedException { |
aoqi@0 | 146 | if (Thread.interrupted()) throw new InterruptedException(); |
aoqi@0 | 147 | synchronized(this) { |
aoqi@0 | 148 | Thread thr = Thread.currentThread(); |
aoqi@0 | 149 | if (holder_ == thr) |
aoqi@0 | 150 | throw new INTERNAL( |
aoqi@0 | 151 | "Attempt to acquire Mutex by thread holding the Mutex" ) ; |
aoqi@0 | 152 | |
aoqi@0 | 153 | try { |
aoqi@0 | 154 | while (inuse_) wait(); |
aoqi@0 | 155 | inuse_ = true; |
aoqi@0 | 156 | holder_ = Thread.currentThread(); |
aoqi@0 | 157 | } |
aoqi@0 | 158 | catch (InterruptedException ex) { |
aoqi@0 | 159 | notify(); |
aoqi@0 | 160 | throw ex; |
aoqi@0 | 161 | } |
aoqi@0 | 162 | } |
aoqi@0 | 163 | } |
aoqi@0 | 164 | |
aoqi@0 | 165 | public synchronized void release() { |
aoqi@0 | 166 | Thread thr = Thread.currentThread(); |
aoqi@0 | 167 | if (thr != holder_) |
aoqi@0 | 168 | throw new INTERNAL( |
aoqi@0 | 169 | "Attempt to release Mutex by thread not holding the Mutex" ) ; |
aoqi@0 | 170 | holder_ = null; |
aoqi@0 | 171 | inuse_ = false; |
aoqi@0 | 172 | notify(); |
aoqi@0 | 173 | } |
aoqi@0 | 174 | |
aoqi@0 | 175 | |
aoqi@0 | 176 | public boolean attempt(long msecs) throws InterruptedException { |
aoqi@0 | 177 | if (Thread.interrupted()) throw new InterruptedException(); |
aoqi@0 | 178 | synchronized(this) { |
aoqi@0 | 179 | Thread thr = Thread.currentThread() ; |
aoqi@0 | 180 | |
aoqi@0 | 181 | if (!inuse_) { |
aoqi@0 | 182 | inuse_ = true; |
aoqi@0 | 183 | holder_ = thr; |
aoqi@0 | 184 | return true; |
aoqi@0 | 185 | } else if (msecs <= 0) |
aoqi@0 | 186 | return false; |
aoqi@0 | 187 | else { |
aoqi@0 | 188 | long waitTime = msecs; |
aoqi@0 | 189 | long start = System.currentTimeMillis(); |
aoqi@0 | 190 | try { |
aoqi@0 | 191 | for (;;) { |
aoqi@0 | 192 | wait(waitTime); |
aoqi@0 | 193 | if (!inuse_) { |
aoqi@0 | 194 | inuse_ = true; |
aoqi@0 | 195 | holder_ = thr; |
aoqi@0 | 196 | return true; |
aoqi@0 | 197 | } |
aoqi@0 | 198 | else { |
aoqi@0 | 199 | waitTime = msecs - (System.currentTimeMillis() - start); |
aoqi@0 | 200 | if (waitTime <= 0) |
aoqi@0 | 201 | return false; |
aoqi@0 | 202 | } |
aoqi@0 | 203 | } |
aoqi@0 | 204 | } |
aoqi@0 | 205 | catch (InterruptedException ex) { |
aoqi@0 | 206 | notify(); |
aoqi@0 | 207 | throw ex; |
aoqi@0 | 208 | } |
aoqi@0 | 209 | } |
aoqi@0 | 210 | } |
aoqi@0 | 211 | } |
aoqi@0 | 212 | } |