You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oz...@apache.org on 2007/08/16 22:26:47 UTC

svn commit: r566828 - in /commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks: ./ ResourceRWLock.java

Author: ozeigermann
Date: Thu Aug 16 13:26:46 2007
New Revision: 566828

URL: http://svn.apache.org/viewvc?view=rev&rev=566828
Log:
Added resource RW lock to suite our special needs

Added:
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java

Added: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java?view=auto&rev=566828
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java (added)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java Thu Aug 16 13:26:46 2007
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.transaction.locking.locks;
+
+import java.util.Collection;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Special version of a {@link ReentrantReadWriteLock}.
+ * 
+ * <ul>
+ * <li>each thread can hold at most one lock level, i.e. either none, read, or
+ * write.
+ * <li>ownership is (also partially) transferable from one thread to another (not in this initial implementation)
+ * <li>upgrade from read-lock to write-lock is supported
+ * <li>information which thread holds which locks is available
+ * </ul>
+ */
+public class ResourceRWLock implements ReadWriteLock {
+
+    private static final long serialVersionUID = -5452408535686743324L;
+
+    private final ResourceRWLock.ReadLock readerLock;
+
+    private final ResourceRWLock.WriteLock writerLock;
+
+    private final Sync sync = new Sync();
+
+    public ResourceRWLock() {
+        readerLock = new ReadLock();
+        writerLock = new WriteLock();
+    }
+
+    public ResourceRWLock.WriteLock writeLock() {
+        return writerLock;
+    }
+
+    public ResourceRWLock.ReadLock readLock() {
+        return readerLock;
+    }
+
+    class ReadLock implements Lock {
+        public void lock() {
+            sync.acquireShared(1);
+        }
+
+        public void lockInterruptibly() throws InterruptedException {
+            sync.acquireSharedInterruptibly(1);
+        }
+
+        public boolean tryLock() {
+            return sync.tryReadLock();
+        }
+
+        public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
+            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+        }
+
+        public void unlock() {
+            sync.releaseShared(1);
+        }
+
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+
+        public String toString() {
+            StringBuffer buf = new StringBuffer();
+            buf.append(super.toString()).append("[Read locks = ");
+            buf.append("]");
+            Collection<Thread> readerThreads = sync.readerThreads;
+            for (Thread thread : readerThreads) {
+                buf.append(thread.getName());
+                buf.append(" ");
+            }
+            return buf.toString();
+        }
+    }
+
+    class WriteLock implements Lock {
+        public void lock() {
+            sync.acquire(1);
+        }
+
+        public void lockInterruptibly() throws InterruptedException {
+            sync.acquireInterruptibly(1);
+        }
+
+        public boolean tryLock() {
+            return sync.tryWriteLock();
+        }
+
+        public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
+            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+        }
+
+        public void unlock() {
+            sync.release(1);
+        }
+
+        public Condition newCondition() {
+            return sync.newCondition();
+        }
+
+        public String toString() {
+            Thread o = sync.getOwner();
+            return super.toString()
+                    + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]");
+        }
+
+    }
+
+    static class Sync extends AbstractQueuedSynchronizer {
+
+        private static final long serialVersionUID = 8791542812047042797L;
+
+        private final Collection<Thread> readerThreads = new ConcurrentSkipListSet<Thread>();
+
+        private final int NO_LOCK = 0;
+
+        private final int SINGLE_READ_LOCK = 1;
+
+        private final int WRITE_LOCK = -1;
+
+        protected boolean tryRelease(int unsused) {
+            Thread current = Thread.currentThread();
+            // gracefully return in case we do not even have the lock
+            if (current != getExclusiveOwnerThread())
+                return true;
+            setExclusiveOwnerThread(null);
+            setState(readerThreads.size());
+            return true;
+        }
+
+        protected boolean tryReleaseShared(int unused) {
+            Thread current = Thread.currentThread();
+            if (readerThreads.remove(current)) {
+                while (true) {
+                    int c = getState();
+                    int nextc = c - 1;
+                    if (c == WRITE_LOCK) {
+                        return true;
+                    }
+
+                    if (!compareAndSetState(c, nextc)) {
+                        // oops, someone was faster than us, so try again
+                        continue;
+                    }
+                    return true;
+
+                }
+            }
+            return true;
+        }
+
+        protected boolean tryAcquire(int unused) {
+            return tryWriteLock();
+        }
+
+        protected int tryAcquireShared(int unused) {
+            return tryReadLock() ? 0 : -1;
+        }
+
+        boolean tryWriteLock() {
+            Thread current = Thread.currentThread();
+            while (true) {
+                int c = getState();
+                if (c == NO_LOCK) {
+                    // if there is no lock, we can safely acquire it as WRITE
+                    if (!compareAndSetState(c, WRITE_LOCK)) {
+                        // oops, someone was faster than us, so try again
+                        continue;
+                    }
+                    setExclusiveOwnerThread(current);
+                    return true;
+                } else if (c == SINGLE_READ_LOCK) {
+                    // if there is a single read lock, we can upgrade to write
+                    // in case we are the one that holds it
+                    if (!readerThreads.contains(current))
+                        return false;
+                    if (!compareAndSetState(c, WRITE_LOCK)) {
+                        // oops, someone was faster than us, so try again
+                        continue;
+                    }
+                    setExclusiveOwnerThread(current);
+                    return true;
+                } else if (c == WRITE_LOCK) {
+                    // if there is a write lock only chance is we already have
+                    // it
+                    return getExclusiveOwnerThread() == current;
+                } else {
+                    // otherwise there must be multiple read locks
+                    // that do not allow to upgrade to a write lock in any case
+                    return false;
+                }
+            }
+        }
+
+        boolean tryReadLock() {
+            Thread current = Thread.currentThread();
+            while (true) {
+                int c = getState();
+                if (c == NO_LOCK) {
+                    // if there is no lock, we can safely acquire it as READ
+                    if (!compareAndSetState(c, SINGLE_READ_LOCK)) {
+                        // oops, someone was faster than us, so try again
+                        continue;
+                    }
+                    readerThreads.add(current);
+                    return true;
+                } else if (c == WRITE_LOCK) {
+                    // if there is a write lock only chance is we already have
+                    // it
+                    return getExclusiveOwnerThread() == current;
+                } else {
+                    // otherwise there must be multiple read locks
+                    // if we are not already one of the reading threads, we add
+                    // ourselves
+                    if (readerThreads.contains(current))
+                        return true;
+                    if (!compareAndSetState(c, c + 1)) {
+                        // oops, someone was faster than us, so try again
+                        continue;
+                    }
+                    readerThreads.add(current);
+                    return true;
+                }
+            }
+        }
+
+        ConditionObject newCondition() {
+            return new ConditionObject();
+        }
+
+        Thread getOwner() {
+            return (getState() == 0 ? null : getExclusiveOwnerThread());
+        }
+
+    }
+
+}