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 */ 017package 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 */ 025public 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}