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: import java.util.concurrent.locks.ReentrantReadWriteLock;
045:
046: /**
047: * Implementation of a regular lock (read/write).
048: * @author Jesse Glick
049: */
050: final class ReadWriteLockWrapper implements DuplexLock {
051:
052: private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(
053: true);
054: /** workaround needed in Tiger; see {@link #canRead} */
055: private final ThreadLocal<Integer> reading = new ThreadLocal<Integer>() {
056: protected Integer initialValue() {
057: return 0;
058: }
059: };
060:
061: public ReadWriteLockWrapper() {
062: }
063:
064: public void enterRead() {
065: lock.readLock().lock();
066: reading.set(reading.get() + 1);
067: }
068:
069: public void exitRead() {
070: lock.readLock().unlock();
071: assert reading.get() > 0;
072: reading.set(reading.get() - 1);
073: }
074:
075: public void enterWrite() {
076: lock.writeLock().lock();
077: }
078:
079: public void exitWrite() {
080: lock.writeLock().unlock();
081: }
082:
083: public void read(Runnable action) {
084: enterRead();
085: try {
086: action.run();
087: } finally {
088: exitRead();
089: }
090: }
091:
092: public void write(Runnable action) {
093: enterWrite();
094: try {
095: action.run();
096: } finally {
097: exitWrite();
098: }
099: }
100:
101: public <T> T read(LockAction<T> action) {
102: enterRead();
103: try {
104: return action.run();
105: } finally {
106: exitRead();
107: }
108: }
109:
110: public <T> T write(LockAction<T> action) {
111: enterWrite();
112: try {
113: return action.run();
114: } finally {
115: exitWrite();
116: }
117: }
118:
119: public <T, E extends Exception> T read(
120: LockExceptionAction<T, E> action) throws E {
121: enterRead();
122: try {
123: return action.run();
124: } catch (RuntimeException e) {
125: throw e;
126: } catch (Exception e) {
127: @SuppressWarnings("unchecked")
128: E _e = (E) e;
129: throw _e;
130: } finally {
131: exitRead();
132: }
133: }
134:
135: public <T, E extends Exception> T write(
136: LockExceptionAction<T, E> action) throws E {
137: enterWrite();
138: try {
139: return action.run();
140: } catch (RuntimeException e) {
141: throw e;
142: } catch (Exception e) {
143: @SuppressWarnings("unchecked")
144: E _e = (E) e;
145: throw _e;
146: } finally {
147: exitWrite();
148: }
149: }
150:
151: public void readLater(final Runnable action) {
152: Worker.start(new Runnable() {
153: public void run() {
154: read(action);
155: }
156: });
157: }
158:
159: public void writeLater(final Runnable action) {
160: Worker.start(new Runnable() {
161: public void run() {
162: write(action);
163: }
164: });
165: }
166:
167: public boolean canRead() {
168: // XXX in JDK 6 can just use: return lock.getReadHoldCount() > 0;
169: return reading.get() > 0;
170: }
171:
172: public boolean canWrite() {
173: return lock.isWriteLockedByCurrentThread();
174: }
175:
176: }
|