| /* |
| * Copyright 1999,2004 The Apache Software Foundation. |
| * |
| * Licensed 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.catalina.cluster.util; |
| |
| /** |
| * The class <b>SingleRemoveSynchronizedAddLock</b> implement locking for accessing the queue |
| * by a single remove thread and multiple add threads. |
| * |
| * A thread is only allowed to be either the remove or |
| * an add thread. |
| * |
| * The lock can either be owned by the remove thread |
| * or by a single add thread. |
| * |
| * If the remove thread tries to get the lock, |
| * but the queue is empty, it will block (poll) |
| * until an add threads adds an entry to the queue and |
| * releases the lock. |
| * |
| * If the remove thread and add threads compete for |
| * the lock and an add thread releases the lock, then |
| * the remove thread will get the lock first. |
| * |
| * The remove thread removes all entries in the queue |
| * at once and proceeses them without further |
| * polling the queue. |
| * |
| * The lock is not reentrant, in the sense, that all |
| * threads must release an owned lock before competing |
| * for the lock again! |
| * |
| * @author Rainer Jung |
| * @author Peter Rossbach |
| * @version 1.1 |
| */ |
| |
| public class SingleRemoveSynchronizedAddLock { |
| |
| public SingleRemoveSynchronizedAddLock() { |
| } |
| |
| public SingleRemoveSynchronizedAddLock(boolean dataAvailable) { |
| this.dataAvailable=dataAvailable; |
| } |
| |
| /** |
| * Time in milliseconds after which threads |
| * waiting for an add lock are woken up. |
| * This is used as a safety measure in case |
| * thread notification via the unlock methods |
| * has a bug. |
| */ |
| private long addWaitTimeout = 10000L; |
| |
| /** |
| * Time in milliseconds after which threads |
| * waiting for a remove lock are woken up. |
| * This is used as a safety measure in case |
| * thread notification via the unlock methods |
| * has a bug. |
| */ |
| private long removeWaitTimeout = 30000L; |
| |
| /** |
| * The current remove thread. |
| * It is set to the remove thread polling for entries. |
| * It is reset to null when the remove thread |
| * releases the lock and proceeds processing |
| * the removed entries. |
| */ |
| private Thread remover = null; |
| |
| /** |
| * A flag indicating, if an add thread owns the lock. |
| */ |
| private boolean addLocked = false; |
| |
| /** |
| * A flag indicating, if the remove thread owns the lock. |
| */ |
| private boolean removeLocked = false; |
| |
| /** |
| * A flag indicating, if the remove thread is allowed |
| * to wait for the lock. The flag is set to false, when aborting. |
| */ |
| private boolean removeEnabled = true; |
| |
| /** |
| * A flag indicating, if the remover needs polling. |
| * It indicates, if the locked object has data available |
| * to be removed. |
| */ |
| private boolean dataAvailable = false; |
| |
| /** |
| * @return Value of addWaitTimeout |
| */ |
| public synchronized long getAddWaitTimeout() { |
| return addWaitTimeout; |
| } |
| |
| /** |
| * Set value of addWaitTimeout |
| */ |
| public synchronized void setAddWaitTimeout(long timeout) { |
| addWaitTimeout = timeout; |
| } |
| |
| /** |
| * @return Value of removeWaitTimeout |
| */ |
| public synchronized long getRemoveWaitTimeout() { |
| return removeWaitTimeout; |
| } |
| |
| /** |
| * Set value of removeWaitTimeout |
| */ |
| public synchronized void setRemoveWaitTimeout(long timeout) { |
| removeWaitTimeout = timeout; |
| } |
| |
| /** |
| * Check if the locked object has data available |
| * i.e. the remover can stop poling and get the lock. |
| * @return True iff the lock Object has data available. |
| */ |
| public synchronized boolean isDataAvailable() { |
| return dataAvailable; |
| } |
| |
| /** |
| * Check if an add thread owns the lock. |
| * @return True iff an add thread owns the lock. |
| */ |
| public synchronized boolean isAddLocked() { |
| return addLocked; |
| } |
| |
| /** |
| * Check if the remove thread owns the lock. |
| * @return True iff the remove thread owns the lock. |
| */ |
| public synchronized boolean isRemoveLocked() { |
| return removeLocked; |
| } |
| |
| /** |
| * Check if the remove thread is polling. |
| * @return True iff the remove thread is polling. |
| */ |
| public synchronized boolean isRemovePolling() { |
| if ( remover != null ) { |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Acquires the lock by an add thread and sets the add flag. |
| * If any add thread or the remove thread already acquired the lock |
| * this add thread will block until the lock is released. |
| */ |
| public synchronized void lockAdd() { |
| if ( addLocked || removeLocked ) { |
| do { |
| try { |
| wait(addWaitTimeout); |
| } catch ( InterruptedException e ) { |
| } |
| } while ( addLocked || removeLocked ); |
| } |
| addLocked=true; |
| } |
| |
| /** |
| * Acquires the lock by the remove thread and sets the remove flag. |
| * If any add thread already acquired the lock or the queue is |
| * empty, the remove thread will block until the lock is released |
| * and the queue is not empty. |
| */ |
| public synchronized boolean lockRemove() { |
| removeLocked=false; |
| removeEnabled=true; |
| if ( ( addLocked || ! dataAvailable ) && removeEnabled ) { |
| remover=Thread.currentThread(); |
| do { |
| try { |
| wait(removeWaitTimeout); |
| } catch ( InterruptedException e ) { |
| } |
| } while ( ( addLocked || ! dataAvailable ) && removeEnabled ); |
| remover=null; |
| } |
| if ( removeEnabled ) { |
| removeLocked=true; |
| } |
| return removeLocked; |
| } |
| |
| /** |
| * Releases the lock by an add thread and reset the remove flag. |
| * If the reader thread is polling, notify it. |
| */ |
| public synchronized void unlockAdd(boolean dataAvailable) { |
| addLocked=false; |
| this.dataAvailable=dataAvailable; |
| if ( ( remover != null ) && ( dataAvailable || ! removeEnabled ) ) { |
| remover.interrupt(); |
| } else { |
| notifyAll(); |
| } |
| } |
| |
| /** |
| * Releases the lock by the remove thread and reset the add flag. |
| * Notify all waiting add threads, |
| * that the lock has been released by the remove thread. |
| */ |
| public synchronized void unlockRemove() { |
| removeLocked=false; |
| dataAvailable=false; |
| notifyAll(); |
| } |
| |
| /** |
| * Abort any polling remover thread |
| */ |
| public synchronized void abortRemove() { |
| removeEnabled=false; |
| if ( remover != null ) { |
| remover.interrupt(); |
| } |
| } |
| |
| } |