Java tutorial
/* * JBoss, Home of Professional Open Source * Copyright 2005, JBoss Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ import java.io.PrintWriter; import java.io.StringWriter; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; /* * JBoss, Home of Professional Open Source Copyright 2005, JBoss Inc., and * individual contributors as indicated by the @authors tag. See the * copyright.txt in the distribution for a full listing of individual * contributors. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this software; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF * site: http://www.fsf.org. */ /** * Wait exclusive semaphore with wait - notify primitives * * @author <a href="mailto:simone.bordet@compaq.com">Simone Bordet</a> * @version $Revision: 1958 $ */ public class WaitSemaphore extends Semaphore implements WaitSync { // Constants ----------------------------------------------------- private final static int MAX_USERS_ALLOWED = 1; // Attributes ---------------------------------------------------- private int m_waiters; // Static -------------------------------------------------------- // Constructors -------------------------------------------------- public WaitSemaphore() { super(MAX_USERS_ALLOWED); } // Public -------------------------------------------------------- public void doWait() throws InterruptedException { synchronized (this) { release(); ++m_waiters; waitImpl(this); --m_waiters; acquire(); } } public void doNotify() throws InterruptedException { synchronized (this) { if (getWaiters() > 0) { acquire(); notify(); release(); } } } public int getWaiters() { synchronized (this) { return m_waiters; } } // Object overrides --------------------------------------------------- public String toString() { return super.toString() + " - " + m_waiters; } // Package protected --------------------------------------------- // Protected ----------------------------------------------------- // Private ------------------------------------------------------- // Inner classes ------------------------------------------------- } /** * Semaphore that can allow a specified number of threads to enter, blocking the * others. If the specified number of threads is 1, it acts as an exclusive * semaphore and can be used instead of synchronized blocks * * @author <a href="mailto:simone.bordet@compaq.com">Simone Bordet</a> * @version $Revision: 2787 $ */ @SuppressWarnings("unchecked") class Semaphore implements Sync { // Constants ----------------------------------------------------- private static final long DEADLOCK_TIMEOUT = 5 * 60 * 1000; // Attributes ---------------------------------------------------- private final static boolean m_debug = false; private int m_users; private int m_allowed; private Map m_logMap; // Static -------------------------------------------------------- // Constructors -------------------------------------------------- public Semaphore(int allowed) { if (allowed < 1) throw new IllegalArgumentException(); m_users = 0; m_allowed = allowed; m_logMap = new HashMap(); } // Public -------------------------------------------------------- public int getUsers() { synchronized (this) { return m_users; } } // Sync implementation ---------------------------------------------- public void acquire() throws InterruptedException { synchronized (this) { logAcquire(); // One user more called acquire, increase users ++m_users; boolean waitSuccessful = false; while (m_allowed <= 0) { waitSuccessful = waitImpl(this); if (!waitSuccessful) { // Dealock was detected, restore status, 'cause it's like a release() // that will probably be never called --m_users; ++m_allowed; } } --m_allowed; } } public void release() { synchronized (this) { logRelease(); --m_users; ++m_allowed; notify(); } } // Object overrides --------------------------------------------------- public String toString() { return super.toString() + " - " + m_users; } // Package protected --------------------------------------------- // Protected ----------------------------------------------------- protected boolean waitImpl(Object lock) throws InterruptedException { // Wait (forever) until notified. To discover deadlocks, // turn on debugging of this class long start = System.currentTimeMillis(); lock.wait(DEADLOCK_TIMEOUT); long end = System.currentTimeMillis(); if ((end - start) > (DEADLOCK_TIMEOUT - 1000)) { logDeadlock(); return false; } return true; } protected void logAcquire() { if (m_debug) { // Check if thread is already mapped Thread thread = Thread.currentThread(); // Create stack trace StringWriter sw = new StringWriter(); new Exception().printStackTrace(new PrintWriter(sw)); String trace = sw.toString(); LinkedList list = (LinkedList) m_logMap.get(thread); if (list != null) { // Thread is mapped // Add info Info prevInfo = (Info) list.getLast(); Info info = new Info(thread, m_users, trace); list.add(info); } else { // Thread is not mapped, create list and add counter list = new LinkedList(); Info info = new Info(thread, m_users, trace); list.add(info); // Map thread m_logMap.put(thread, list); } } } protected void logDeadlock() { System.err.println(); System.err.println("DEADLOCK ON SEMAPHORE " + this); if (m_debug) { for (Iterator i = m_logMap.values().iterator(); i.hasNext();) { LinkedList list = (LinkedList) i.next(); for (Iterator iter = list.iterator(); iter.hasNext();) { System.err.println(iter.next()); } } } System.err.println(); } protected void logRelease() { if (m_debug) { // Find a matching thread and remove info for it Thread thread = Thread.currentThread(); LinkedList list = (LinkedList) m_logMap.get(thread); if (list != null) { Info info = new Info(thread, 0, ""); if (!list.remove(info)) { System.err.println("LOG INFO SIZE: " + list); new IllegalStateException("BUG: semaphore log list does not contain required info") .printStackTrace(); } // If no info left, remove the mapping int size = list.size(); if (size < 1) { m_logMap.remove(thread); } } else { throw new IllegalStateException("Semaphore log failed: release called without acquire"); } } } // Private ------------------------------------------------------- // Inner classes ------------------------------------------------- private class Info { private Info(Thread t, int i, String s) { m_thread = t; m_counter = i; m_trace = s; } private Thread m_thread; private int m_counter; private String m_trace; public boolean equals(Object o) { Info other = (Info) o; return m_thread == other.m_thread; } public String toString() { return m_thread + " - " + m_counter + "\n" + m_trace; } } } /* * JBoss, Home of Professional Open Source Copyright 2005, JBoss Inc., and * individual contributors as indicated by the @authors tag. See the * copyright.txt in the distribution for a full listing of individual * contributors. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this software; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF * site: http://www.fsf.org. */ /** * Interface that gives synchronization semantic to implementors * * @see Semaphore * * @author <a href="mailto:simone.bordet@compaq.com">Simone Bordet</a> * @version $Revision: 2787 $ */ interface Sync { /** * Acquires this sync * * @see #release * @throws InterruptedException */ void acquire() throws InterruptedException; /** * Releases this sync * * @see #acquire */ void release(); } /* * JBoss, Home of Professional Open Source Copyright 2005, JBoss Inc., and * individual contributors as indicated by the @authors tag. See the * copyright.txt in the distribution for a full listing of individual * contributors. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this software; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF * site: http://www.fsf.org. */ /** * Interface that gives wait - notify primitives to implementors. * * @see Semaphore * * @author <a href="mailto:simone.bordet@compaq.com">Simone Bordet</a> * @version $Revision: 2787 $ */ interface WaitSync extends Sync { /** * Pone in wait status this sync, until {@link #doNotify} is called to wake it * up. * * @see #doNotify * @throws InterruptedException */ void doWait() throws InterruptedException; /** * Wakes up this sync that has been posed in wait status by a {@link #doWait} * call. If this sync is not waiting, invoking this method should have no * effect. * * @see #doWait * @throws InterruptedException */ void doNotify() throws InterruptedException; }