com.github.thehilikus.jrobocom.timing.Delayer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jrobocom-core Show documentation
Show all versions of jrobocom-core Show documentation
The game core infrastructure
package com.github.thehilikus.jrobocom.timing;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A class that blocks threads for a specified number of cycles. A separate thread needs to make the
* delayer tick
*
* @author hilikus
* @see MasterClock
*/
public class Delayer {
private volatile long cycles;
private List blockedCollection = new CopyOnWriteArrayList<>();
private Logger log = LoggerFactory.getLogger(Delayer.class);
private List registered = new ArrayList<>();
private List waitingList = new ArrayList<>();
/**
* Blocks the calling thread until enough turns have elapsed
*
* @param cyclesToBlock number of ticks to block
*/
private void blockMe(int cyclesToBlock) {
long unblock = cycles + cyclesToBlock;
BlockedEntry newEntry = new BlockedEntry(unblock);
blockedCollection.add(newEntry);
while (unblock > cycles) {
try {
newEntry.getSync().acquire(); // blocks
} catch (InterruptedException exc) {
log.error("[temporaryBlock] Spurious wakeup", exc);
}
}
}
/**
* Signals one cycles has elapsed
*/
public void tick() {
log.trace("Tick {}", cycles);
cycles++;
// check for robots up for unblocking
for (BlockedEntry entry : blockedCollection) {
if (entry.getTimeout() >= cycles) {
entry.getSync().release();
}
}
}
/**
* Registers an object interested in notifications
*
* @param listenerId a unique ID of the listener
*/
public void addListener(int listenerId) {
registered.add(listenerId);
}
/**
* Removes an interested object
*
* @param listenerId a unique ID of the listener
*/
public void removeListener(int listenerId) {
registered.remove(Integer.valueOf(listenerId));
}
/**
* Blocks the calling thread for the specified number of cycles
*
* @param clientId unique ID of the client.
* @param turns the number of clock ticks to block
* @param reason explanation for the wait
*/
public void waitFor(Integer clientId, int turns, String reason) {
// for safety, check if we know the robot, otherwise fail
if (!registered.contains(clientId)) {
throw new IllegalArgumentException("Unknown robot. All robots must first register with clock");
}
synchronized (waitingList) {
if (waitingList.contains(clientId)) {
throw new IllegalArgumentException("Client " + clientId
+ " is already waiting, no multithreading is allowed");
}
waitingList.add(clientId);
}
// we are in the robot's thread
log.trace("[waitFor] Blocking {} for {} turns. Reason: {}", clientId, turns, reason);
blockMe(turns);
log.trace("[waitFor] Unblocked {} - {}", clientId, reason);
synchronized (waitingList) {
waitingList.remove(clientId);
}
}
/**
* cleans all the registered listeners and waiting clients
*/
public void clean() {
if (registered != null) {
registered.clear();
}
if (waitingList != null) {
waitingList.clear();
}
}
}