/*
* This file is part of DLect. DLect is a suite of code that facilitates the downloading of lecture recordings.
*
* Copyright © 2014 Lee Symes.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.dlect.lock;
import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Synchronize "on an equivalence class"; i.e., if you wish to lock not a
* specific string, but anything that equals that string, you may
*
* <pre>EquivalenceLock<String> equivalenceLock = new EquivalenceLock<String>();
* equivalenceLock.lock("frank");
* try {
* // whatever
* } finally {
* equivalenceLock.release("frank");
* }</pre>
*
* @author Jonathan Feinberg <jdf@pobox.com>
* @param <T>
*/
public class EquivalenceLock<T> {
private static final Logger LOG = LoggerFactory.getLogger(EquivalenceLock.class.getName());
private final Set<T> slots = new HashSet<>();
public void lock(final T ticket) throws InterruptedException {
final String threadName = Thread.currentThread().getName();
LOG.trace(threadName + " acquiring lock on tickets");
synchronized (slots) {
LOG.trace(threadName + " acquired lock on tickets");
while (slots.contains(ticket)) {
LOG.trace(threadName + " waiting to toss " + ticket);
slots.wait();
}
LOG.trace(threadName + " accepting " + ticket);
slots.add(ticket);
}
}
public void lockSafe(final T ticket) {
while (true) {
try {
lock(ticket);
return;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.trace("Exception caught in lockSafe", e);
}
}
}
public void release(final T ticket) {
synchronized (slots) {
LOG.trace(Thread.currentThread().getName() + " tossing " + ticket);
slots.remove(ticket);
slots.notifyAll();
}
}
}