package com.ximple.io.dgn7; //~--- JDK imports ------------------------------------------------------------ import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; /** * Lock * * @author Ulysses * @version 0.1 * @since 2006/5/18 上午 10:27:24 */ public class Lock { Logger logger = LogManager.getLogger("com.ximple.io.dgn7"); /** * indicates a write is occurring */ int writeLocks = 0; /** * if not null a writer is waiting for the lock or is writing. */ Thread writer; /** * Thread->Owner map. If empty no read locks exist. */ Map owners = new HashMap(); /** * If the lock can be read locked the lock will be read and default * visibility for tests * * @return * @throws java.io.IOException */ synchronized boolean canRead() throws IOException { if ((writer != null) && (writer != Thread.currentThread())) { return false; } if (writer == null) { return true; } if (owners.size() > 1) { return false; } return true; } /** * If the lock can be read locked the lock will be read and default * visibility for tests * * @return * @throws IOException */ synchronized boolean canWrite() throws IOException { if (owners.size() > 1) { return false; } if ((canRead()) && ((writer == Thread.currentThread()) || (writer == null))) { if (owners.isEmpty()) { return true; } if (owners.containsKey(Thread.currentThread())) { return true; } } return false; } /** * Called by shapefileReader before a read is started and before an IOStream * is openned. * * @throws IOException */ public synchronized void lockRead() throws IOException { if (!canRead()) { while ((writeLocks > 0) || (writer != null)) { try { wait(); } catch (InterruptedException e) { throw(IOException) new IOException().initCause(e); } } } assertTrue("A write lock exists that is owned by another thread", canRead()); Thread current = Thread.currentThread(); Owner owner = (Owner) owners.get(current); if (owner != null) { owner.timesLocked++; } else { owner = new Owner(current); owners.put(current, owner); } logger.debug("Start Read Lock:" + owner); } private void assertTrue(String message, boolean b) { if (!b) { throw new AssertionError(message); } } /** * Called by ShapefileReader after a read is complete and after the IOStream * is closed. */ public synchronized void unlockRead() { assertTrue("Current thread does not have a readLock", owners.containsKey(Thread.currentThread())); Owner owner = (Owner) owners.get(Thread.currentThread()); assertTrue("Current thread has " + owner.timesLocked + "negative number of locks", owner.timesLocked > 0); owner.timesLocked--; if (owner.timesLocked == 0) { owners.remove(Thread.currentThread()); } notifyAll(); logger.debug("unlock Read:" + owner); } /** * Called by ShapefileDataStore before a write is started and before an * IOStream is openned. * * @throws IOException */ public synchronized void lockWrite() throws IOException { Thread currentThread = Thread.currentThread(); if (writer == null) { writer = currentThread; } while (!canWrite()) { try { wait(); } catch (InterruptedException e) { throw(IOException) new IOException().initCause(e); } if (writer == null) { writer = currentThread; } } if (writer == null) { writer = currentThread; } assertTrue("The current thread is not the writer", writer == currentThread); assertTrue("There are read locks not belonging to the current thread.", canRead()); writeLocks++; logger.debug(currentThread.getName() + " is getting write lock:" + writeLocks); } /** * default visibility for tests */ synchronized int getReadLocks(Thread thread) { Owner owner = (Owner) owners.get(thread); if (owner == null) { return -1; } return owner.timesLocked; } public synchronized void unlockWrite() { if (writeLocks > 0) { assertTrue("current thread does not own the write lock", writer == Thread.currentThread()); assertTrue("writeLock has already been unlocked", writeLocks > 0); writeLocks--; if (writeLocks == 0) { writer = null; } } logger.debug("unlock write:" + Thread.currentThread().getName()); notifyAll(); } /** * default visibility for tests */ synchronized boolean ownWriteLock(Thread thread) { return (writer == thread) && (writeLocks > 0); } private class Owner { final Thread owner; int timesLocked; Owner(Thread owner) { this.owner = owner; timesLocked = 1; } public String toString() { return owner.getName() + " has " + timesLocked + " locks"; } } }