/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.util.concurrency;
/**
* Implements a Semaphore by using synchronized blocks.
* The concept of Semaphores is well described in Doug Lea: "Concurrent
* Programming in Java", Second Edition, Sun Microsystems.
* Online: http://java.sun.com/Series/docs/books/cp/
*/
public class Semaphore {
/**
* The number of thread that still can enter the critical section at this
* moment.
*/
private int count;
/**
* The total number of threads that can enter the critical section.
*/
private int initialCount;
/**
* Constructs a Semaphore that allows count threads to enter the critical section
* (section between acquire and release) at once.
*
* @param count maximal number of threads that can enter the critical section at once.
* @param initialValue number of threads that can enter the critical section after
* construction (useful for several algorithms).
*/
public Semaphore(int count,int initialValue) {
this.count = initialValue;
this.initialCount = count;
if (count<=0)
throw new RuntimeException("Semaphore construction exception: count has to be greater than 0.");
}
/**
* Constructs a Semaphore that allows only thread to be in the critical section
* at once.
*/
public Semaphore() {
this(1,1);
}
/**
* Acquires the Semaphore. This Method stops the current thread if
* the internal counter of the semaphore
*/
public synchronized void acquire() {
while (count==0) {
try {
wait();
}
catch (InterruptedException e) {}
}
count--;
}
/**
* Releases the Semaphore and wakes up a waiting thread.
*/
public synchronized void release() {
count++;
if (count>initialCount)
throw new RuntimeException("Semaphore exception: release is called too often");
// let the next waiting thread continue execution
notify();
}
/**
* Tries to acquire the Semaphore but does not wait. If false is
* returned no lock has been acquired.
*
* Example:
* <code>
* if (s.attempt()) {
* ... do something ...
* s.release();
* }
* </code>
* @return true if acquired
*/
public synchronized boolean attempt() {
if (count>0) {
count--;
return true;
}
else
return false;
}
/**
* Tries to acquire the Semaphore and waits msecs at most. If false is
* returned no lock has been acquired.
*
* Example:
* <code>
* if (s.attempt(1000)) {
* ... do something ...
* s.release();
* }
* </code>
* @param msecs maximum timeout to wait
* @return true if acquired
*
*/
public boolean attempt(int msecs) {
boolean state = attempt();
if (state)
return true;
else {
synchronized (this) {
try {
wait(msecs);
}
catch (InterruptedException e) {}
// must be in a synchronized statement because if the
// waiting thread receives a notification, he should
// be the one that gets the next lock.
return attempt();
}
}
}
/**
* Writes the current state into a string (for debugging purposes).
* Do not use something like that:
*
* if (sem.toString().equals("1") {
* critical section
* }
*
* @return returns current state as a string
*/
public String toString() {
synchronized (this) {
return String.valueOf(count);
}
}
}