001: /*
002: File: ReentrantLock.java
003:
004: Originally written by Doug Lea and released into the public domain.
005: This may be used for any purposes whatsoever without acknowledgment.
006: Thanks for the assistance and support of Sun Microsystems Labs,
007: and everyone contributing, testing, and using this code.
008:
009: History:
010: Date Who What
011: 11Jun1998 dl Create public version
012: 5Aug1998 dl replaced int counters with longs
013: */
014:
015: package EDU.oswego.cs.dl.util.concurrent;
016:
017: /**
018: * A lock with the same semantics as builtin
019: * Java synchronized locks: Once a thread has a lock, it
020: * can re-obtain it any number of times without blocking.
021: * The lock is made available to other threads when
022: * as many releases as acquires have occurred.
023: * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
024: **/
025:
026: public class ReentrantLock implements Sync {
027:
028: protected Thread owner_ = null;
029: protected long holds_ = 0;
030:
031: public void acquire() throws InterruptedException {
032: if (Thread.interrupted())
033: throw new InterruptedException();
034: Thread caller = Thread.currentThread();
035: synchronized (this ) {
036: if (caller == owner_)
037: ++holds_;
038: else {
039: try {
040: while (owner_ != null)
041: wait();
042: owner_ = caller;
043: holds_ = 1;
044: } catch (InterruptedException ex) {
045: notify();
046: throw ex;
047: }
048: }
049: }
050: }
051:
052: public boolean attempt(long msecs) throws InterruptedException {
053: if (Thread.interrupted())
054: throw new InterruptedException();
055: Thread caller = Thread.currentThread();
056: synchronized (this ) {
057: if (caller == owner_) {
058: ++holds_;
059: return true;
060: } else if (owner_ == null) {
061: owner_ = caller;
062: holds_ = 1;
063: return true;
064: } else if (msecs <= 0)
065: return false;
066: else {
067: long waitTime = msecs;
068: long start = System.currentTimeMillis();
069: try {
070: for (;;) {
071: wait(waitTime);
072: if (caller == owner_) {
073: ++holds_;
074: return true;
075: } else if (owner_ == null) {
076: owner_ = caller;
077: holds_ = 1;
078: return true;
079: } else {
080: waitTime = msecs
081: - (System.currentTimeMillis() - start);
082: if (waitTime <= 0)
083: return false;
084: }
085: }
086: } catch (InterruptedException ex) {
087: notify();
088: throw ex;
089: }
090: }
091: }
092: }
093:
094: /**
095: * Release the lock.
096: * @exception Error thrown if not current owner of lock
097: **/
098: public synchronized void release() {
099: if (Thread.currentThread() != owner_)
100: throw new Error("Illegal Lock usage");
101:
102: if (--holds_ == 0) {
103: owner_ = null;
104: notify();
105: }
106: }
107:
108: /**
109: * Release the lock N times. <code>release(n)</code> is
110: * equivalent in effect to:
111: * <pre>
112: * for (int i = 0; i < n; ++i) release();
113: * </pre>
114: * <p>
115: * @exception Error thrown if not current owner of lock
116: * or has fewer than N holds on the lock
117: **/
118: public synchronized void release(long n) {
119: if (Thread.currentThread() != owner_ || n > holds_)
120: throw new Error("Illegal Lock usage");
121:
122: holds_ -= n;
123: if (holds_ == 0) {
124: owner_ = null;
125: notify();
126: }
127: }
128:
129: /**
130: * Return the number of unreleased acquires performed
131: * by the current thread.
132: * Returns zero if current thread does not hold lock.
133: **/
134: public synchronized long holds() {
135: if (Thread.currentThread() != owner_)
136: return 0;
137: return holds_;
138: }
139:
140: }
|