001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.transaction.util;
018
019 /**
020 * Simple barrier that blocks until all parties have either called or have arrived at the meeting point.
021 * Very useful for testing or other purposes that require to make concurrent settings deterministic.
022 *
023 * @version $Id: RendezvousBarrier.java 493628 2007-01-07 01:42:48Z joerg $
024 */
025 public class RendezvousBarrier {
026
027 public static final int DEFAULT_TIMEOUT = 20000;
028
029 protected final int parties;
030 protected final String name;
031 protected int count = 0;
032 protected long timeout;
033 protected LoggerFacade logger;
034
035 public RendezvousBarrier(String name, LoggerFacade logger) {
036 this(name, DEFAULT_TIMEOUT, logger);
037 }
038
039 public RendezvousBarrier(String name, long timeout, LoggerFacade logger) {
040 this(name, 2, timeout, logger);
041 }
042
043 public RendezvousBarrier(String name, int parties, long timeout, LoggerFacade logger) {
044 this.parties = parties;
045 this.name = name;
046 this.timeout = timeout;
047 this.logger = logger;
048 }
049
050 /**
051 * Notify the barrier that you (the current thread) will not come to the meeting point.
052 * Same thing as {@link #meet()}, but does not not let you wait.
053 */
054 public synchronized void call() {
055 count++;
056 if (count >= parties) {
057 if (logger.isFineEnabled())
058 logger.logFine("Thread " + Thread.currentThread().getName() + " by CALL COMPLETING barrier " + name);
059 notifyAll();
060 }
061 }
062
063 /**
064 * Meet at this barrier. The current thread will either block when there are missing parties for this barrier
065 * or it is the last one to complete this meeting and the barrier will release its block.
066 * In this case all other waiting threads will be notified.
067 *
068 * @throws InterruptedException if the current thread is interrupted while waiting
069 */
070 public synchronized void meet() throws InterruptedException {
071 count++;
072 if (count >= parties) {
073 if (logger.isFineEnabled())
074 logger.logFine("Thread " + Thread.currentThread().getName() + " by MEET COMPLETING barrier " + name);
075 notifyAll();
076 } else {
077 if (logger.isFineEnabled()) {
078 logger.logFine(
079 "At barrier "
080 + name
081 + " thread "
082 + Thread.currentThread().getName()
083 + " WAITING for "
084 + (parties - count)
085 + " of "
086 + parties
087 + " parties");
088 }
089 wait(timeout);
090 if (count == 0) {
091 // means the barrier has been reset
092 } else if (count >= parties) {
093 if (logger.isFineEnabled())
094 logger.logFine("Thread " + Thread.currentThread().getName() + " CONTINUING at barrier " + name);
095 } else {
096 if (logger.isFineEnabled())
097 logger.logFine("Thread " + Thread.currentThread().getName() + " FAILING at barrier " + name);
098 notifyAll();
099 }
100 }
101 }
102
103 /**
104 * Releases all waiting threads and resets the number of parties already arrived.
105 */
106 public synchronized void reset() {
107 if (logger.isFineEnabled()) logger.logFine("Resetting barrier " + name);
108 count = 0;
109 notifyAll();
110 }
111
112 }