001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package threaddemo.locking;
043:
044: /**
045: * Ability to acquire or release a lock by itself.
046: * This class can be used when one wants to avoid creating a
047: * bunch of Runnables. Instead use:
048: * <pre>
049: * p.enter*();
050: * try {
051: * // your code here
052: * } finally {
053: * p.exit*();
054: * }
055: * </pre>
056: * You must be careful to match enter and exit calls reliably and exactly.
057: * Please read the Javadoc for each method carefully.
058: *
059: * <p>You must control the related Lock, i.e. you must be the creator of
060: * the Lock. Thus you may create a PrivilegedLock for efficient access within
061: * a package and only expose the lock to outside code, to ensure that it is
062: * not abused by being entered and not exited.
063: * @see Lock
064: */
065: public final class PrivilegedLock {
066:
067: private DuplexLock parent;
068:
069: /** Create a new privileged key to a lock.
070: * (It may only be used in one lock.)
071: */
072: public PrivilegedLock() {
073: }
074:
075: final synchronized void setParent(DuplexLock parent) {
076: if (this .parent != null)
077: throw new IllegalStateException();
078: this .parent = parent;
079: }
080:
081: /**
082: * Get the associated lock.
083: * You must have already created a lock with this privileged handle.
084: * @return the lock associated with this object
085: */
086: public RWLock getLock() {
087: if (parent == null)
088: throw new IllegalStateException("Unbound PrivilegedLock"); // NOI18N
089: return parent;
090: }
091:
092: /** Enter read access for this lock.
093: * <strong>You must ensure that {@link #exitRead} is reliably called
094: * when you are done.</strong> The normal way to do this is as follows:
095: * <pre>
096: * p.enterRead();
097: * // must be no additional code here!
098: * try {
099: * // whatever code...
100: * } finally {
101: * // must be no additional code here!
102: * p.exitRead();
103: * }
104: * </pre>
105: *
106: * <p>Detailed behavior:
107: * <ol>
108: * <li>You may already be holding the read or write lock. But you must
109: * still nest entries and exits, 1-to-1.
110: * <li>If this lock has a level, you may not enter it if you are already
111: * holding another lock with a smaller or equal level in this thread.
112: * <li>If another thread is holding the write lock, <strong>this method
113: * will block</strong> until it leaves.
114: * </ol>
115: *
116: */
117: public void enterRead() {
118: parent.enterRead();
119: }
120:
121: /** Enter write access for this lock.
122: * <strong>You must ensure that {@link #exitWrite} is reliably called
123: * when you are done.</strong> The normal way to do this is as follows:
124: * <pre>
125: * p.enterWrite();
126: * // must be no additional code here!
127: * try {
128: * // whatever code...
129: * } finally {
130: * // must be no additional code here!
131: * p.exitWrite();
132: * }
133: * </pre>
134: *
135: * <p>Detailed behavior:
136: * <ol>
137: * <li>You may already be holding the write lock. But you must
138: * still nest entries and exits, 1-to-1.
139: * <li><strong>You may not be holding the read lock</strong> - even if inside
140: * the write lock.
141: * <li>If this lock has a level, you may not enter it if you are already
142: * holding another lock with a smaller or equal level in this thread.
143: * <li>If other threads are holding the read or write lock, <strong>this method
144: * will block</strong> until they all leave.
145: * </ol>
146: *
147: */
148: public void enterWrite() {
149: parent.enterWrite();
150: }
151:
152: /** Exit the read lock.
153: * For important usage instructions, see {@link #enterRead}.
154: *
155: * <p>Detailed behavior:
156: * <ol>
157: * <li>You must have already entered this lock in read mode (once for
158: * every time you exit it).
159: * <li>You must exit a lock in the same thread you entered it.
160: * <li>If this lock has a level, it must be the last lock with a level
161: * which you entered in this thread. You cannot interleave exits of
162: * locks with levels; they must nest.
163: * <li>If this read access is inside another read access, this method
164: * will return immediately.
165: * <li>If this read access is the outermost read access, and not inside any
166: * write access, it will return immediately.
167: * <li>If this read access is the outermost read access within a write access,
168: * it will return immediately.
169: * </ol>
170: *
171: */
172: public void exitRead() {
173: parent.exitRead();
174: }
175:
176: /** Exit the write lock.
177: * For important usage instructions, see {@link #enterWrite}.
178: *
179: * <p>Detailed behavior:
180: * <ol>
181: * <li>You must have already entered this lock in write mode (once for
182: * every time you exit it).
183: * <li>You must exit a lock in the same thread you entered it.
184: * <li>If this lock has a level, it must be the last lock with a level
185: * which you entered in this thread. You cannot interleave exits of
186: * locks with levels; they must nest.
187: * <li>If this write access is inside another write access, this method
188: * will return immediately.
189: * <li>If this write access is the outermost write access, it will return
190: * immediately.
191: * </ol>
192: *
193: */
194: public void exitWrite() {
195: parent.exitWrite();
196: }
197:
198: }
|