001 package org.apache.qpid.util.concurrent;
002 /*
003 *
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 *
021 */
022
023
024 import java.util.concurrent.locks.AbstractQueuedSynchronizer;
025
026 /**
027 * A BooleanLatch is like a set of traffic lights, where threads can wait at a red light until another thread gives
028 * the green light. When threads arrive at the latch it is initially red. They queue up until the green signal is
029 * given, at which point they can all acquire the latch in shared mode and continue to run concurrently. Once the latch
030 * is signalled it cannot be reset to red again.
031 *
032 * <p/> The latch uses a {@link java.util.concurrent.locks.AbstractQueuedSynchronizer} to implement its synchronization.
033 * This has two internal states, 0 which means that the latch is blocked, and 1 which means that the latch is open.
034 *
035 * <p/><table id="crc"><caption>CRC Card</caption>
036 * <tr><th> Responsibilities <th> Collaborations
037 * <tr><td> Block threads until a go signal is given.
038 * </table>
039 *
040 * @todo Might be better to use a countdown latch to count down from 1. Its await method can throw interrupted
041 * exception which makes the possibility of interruption more explicit, and provides a reminder to recheck the
042 * latch condition before continuing.
043 */
044 public class BooleanLatch
045 {
046 /** Holds the synchronizer that provides the thread queueing synchronization. */
047 private final Sync sync = new Sync();
048
049 /**
050 * Tests whether or not the latch has been signalled, that is to say that, the light is green.
051 *
052 * <p/>This method is non-blocking.
053 *
054 * @return <tt>true</tt> if the latch may be acquired; the light is green.
055 */
056 public boolean isSignalled()
057 {
058 return sync.isSignalled();
059 }
060
061 /**
062 * Waits on the latch until the signal is given and the light is green. If the light is already green then the
063 * latch will be acquired and the thread will not have to wait.
064 *
065 * <p/>This method will block until the go signal is given or the thread is otherwise interrupted. Before carrying
066 * out any processing threads that return from this method should confirm that the go signal has really been given
067 * on this latch by calling the {@link #isSignalled()} method.
068 */
069 public void await()
070 {
071 sync.acquireShared(1);
072 }
073
074 /**
075 * Releases any threads currently waiting on the latch. This flips the light to green allowing any threads that
076 * were waiting for this condition to now run.
077 *
078 * <p/>This method is non-blocking.
079 */
080 public void signal()
081 {
082 sync.releaseShared(1);
083 }
084
085 /**
086 * Implements a thread queued synchronizer. The internal state 0 means that the queue is blocked and the internl
087 * state 1 means that the queue is released and that all waiting threads can acquire the synchronizer in shared
088 * mode.
089 */
090 private static class Sync extends AbstractQueuedSynchronizer
091 {
092 /**
093 * Attempts to acquire this synchronizer in shared mode. It may be acquired once it has been released.
094 *
095 * @param ignore This parameter is ignored.
096 *
097 * @return 1 if the shared acquisition succeeds and -1 if it fails.
098 */
099 protected int tryAcquireShared(int ignore)
100 {
101 return isSignalled() ? 1 : -1;
102 }
103
104 /**
105 * Releases the synchronizer, setting its internal state to 1.
106 *
107 * @param ignore This parameter is ignored.
108 *
109 * @return <tt>true</tt> always.
110 */
111 protected boolean tryReleaseShared(int ignore)
112 {
113 setState(1);
114
115 return true;
116 }
117
118 /**
119 * Tests if the synchronizer is signalled. It is signalled when its internal state it 1.
120 *
121 * @return <tt>true</tt> if the internal state is 1, <tt>false</tt> otherwise.
122 */
123 boolean isSignalled()
124 {
125 return getState() != 0;
126 }
127 }
128 }
|