[jboss-cvs] JBossCache/src/org/jboss/cache/lock ...

Manik Surtani manik at jboss.org
Tue Jun 19 06:45:43 EDT 2007


  User: msurtani
  Date: 07/06/19 06:45:43

  Added:       src/org/jboss/cache/lock  StripedLock.java
  Log:
  CL thread safety
  
  Revision  Changes    Path
  1.1      date: 2007/06/19 10:45:43;  author: msurtani;  state: Exp;JBossCache/src/org/jboss/cache/lock/StripedLock.java
  
  Index: StripedLock.java
  ===================================================================
  package org.jboss.cache.lock;
  
  import net.jcip.annotations.ThreadSafe;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jboss.cache.Fqn;
  
  import java.util.concurrent.locks.ReentrantReadWriteLock;
  
  /**
   * A simple implementation of lock striping, using Fqns as the keys to lock on, primarily used to help make
   * {@link org.jboss.cache.loader.CacheLoader} implemtations thread safe.
   * <p/>
   * Backed by a set of {@link java.util.concurrent.locks.ReentrantReadWriteLock} instances, and using the {@link org.jboss.cache.Fqn}
   * hashcodes to determine buckets.
   * <p/>
   * Since buckets are used, it doesn't matter that the Fqn in question is not removed from the lock map when no longer in
   * use, since the Fqn is not referenced in this class.  Rather, the hash code is used.
   * <p/>
   *
   * @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
   * @since 2.0.0
   */
  @ThreadSafe
  public class StripedLock
  {
     private static final int DEFAULT_CONCURRENCY = 20;
     private int lockSegmentMask;
     private int lockSegmentShift;
  
     private ReentrantReadWriteLock[] sharedLocks;
     private Log log = LogFactory.getLog(StripedLock.class);
  
  
     /**
      * This constructor just calls {@link #StripedLock(int)} with a default concurrency value of 20.
      */
     public StripedLock()
     {
        this(DEFAULT_CONCURRENCY);
     }
  
     /**
      * Creates a new StripedLock which uses a certain number of shared locks across all elements that need to be locked.
      *
      * @param concurrency number of threads expected to use this class concurrently.
      */
     public StripedLock(int concurrency)
     {
        int tempLockSegShift = 0;
        int numLocks = 1;
        while (numLocks < concurrency)
        {
           ++tempLockSegShift;
           numLocks <<= 1;
        }
        lockSegmentShift = 32 - tempLockSegShift;
        lockSegmentMask = numLocks - 1;
  
        sharedLocks = new ReentrantReadWriteLock[numLocks];
  
        for (int i = 0; i < numLocks; i++) sharedLocks[i] = new ReentrantReadWriteLock();
     }
  
     /**
      * Blocks until a lock is acquired.
      *
      * @param fqn       the Fqn to lock on
      * @param writeLock if true, a write (exclusive) lock is attempted, otherwise a read (shared) lock is used.
      */
     public void acquireLock(Fqn fqn, boolean writeLock)
     {
        ReentrantReadWriteLock lock = getLock(fqn);
  //      log.error("I want a " + (writeLock ? "WL" : "RL") + " and lock ownership is " + lock.toString());
  
        if (writeLock)
           lock.writeLock().lock();
        else
           lock.readLock().lock();
     }
  
     /**
      * Releases a lock the caller may be holding.
      *
      * @param fqn the Fqn to release
      */
     public void releaseLock(Fqn fqn)
     {
        ReentrantReadWriteLock lock = getLock(fqn);
  //      log.error("I want to release the lock.  Status " + lock);
        try
        {
           lock.readLock().unlock();
        }
        catch (IllegalMonitorStateException imsa)
        {
           log.trace("Caught exception attempting to release a read lock.  Perhaps we have a write lock?");
           lock.writeLock().unlock();
        }
     }
  
     protected ReentrantReadWriteLock getLock(Object o)
     {
        return sharedLocks[hashToIndex(o)];
     }
  
     protected int hashToIndex(Object o)
     {
        return (hash(o) >>> lockSegmentShift) & lockSegmentMask;
     }
  
     /**
      * Returns a hash code for non-null Object x.
      * Uses the same hash code spreader as most other java.util hash tables.
      *
      * @param x the object serving as a key
      * @return the hash code
      */
     private int hash(Object x)
     {
        int h = x.hashCode();
        h += ~(h << 9);
        h ^= (h >>> 14);
        h += (h << 4);
        h ^= (h >>> 10);
        return h;
     }
  }
  
  
  



More information about the jboss-cvs-commits mailing list