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,
040: LoggerFacade logger) {
041: this (name, 2, timeout, logger);
042: }
043:
044: public RendezvousBarrier(String name, int parties, long timeout,
045: LoggerFacade logger) {
046: this .parties = parties;
047: this .name = name;
048: this .timeout = timeout;
049: this .logger = logger;
050: }
051:
052: /**
053: * Notify the barrier that you (the current thread) will not come to the meeting point.
054: * Same thing as {@link #meet()}, but does not not let you wait.
055: */
056: public synchronized void call() {
057: count++;
058: if (count >= parties) {
059: if (logger.isFineEnabled())
060: logger.logFine("Thread "
061: + Thread.currentThread().getName()
062: + " by CALL COMPLETING barrier " + name);
063: notifyAll();
064: }
065: }
066:
067: /**
068: * Meet at this barrier. The current thread will either block when there are missing parties for this barrier
069: * or it is the last one to complete this meeting and the barrier will release its block.
070: * In this case all other waiting threads will be notified.
071: *
072: * @throws InterruptedException if the current thread is interrupted while waiting
073: */
074: public synchronized void meet() throws InterruptedException {
075: count++;
076: if (count >= parties) {
077: if (logger.isFineEnabled())
078: logger.logFine("Thread "
079: + Thread.currentThread().getName()
080: + " by MEET COMPLETING barrier " + name);
081: notifyAll();
082: } else {
083: if (logger.isFineEnabled()) {
084: logger.logFine("At barrier " + name + " thread "
085: + Thread.currentThread().getName()
086: + " WAITING for " + (parties - count) + " of "
087: + parties + " 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 "
095: + Thread.currentThread().getName()
096: + " CONTINUING at barrier " + name);
097: } else {
098: if (logger.isFineEnabled())
099: logger.logFine("Thread "
100: + Thread.currentThread().getName()
101: + " FAILING at barrier " + name);
102: notifyAll();
103: }
104: }
105: }
106:
107: /**
108: * Releases all waiting threads and resets the number of parties already arrived.
109: */
110: public synchronized void reset() {
111: if (logger.isFineEnabled())
112: logger.logFine("Resetting barrier " + name);
113: count = 0;
114: notifyAll();
115: }
116:
117: }
|