1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
package tim.prune.gui.map.tile;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
public class TileWorkerCoordinator implements Coordinator
{
private final TileManager _parent;
private final TileWorkerBuilder _builder;
private final LinkedList<TileDef> _waitingDefs = new LinkedList<>();
private final HashSet<TileDef> _processingDefs = new HashSet<>();
private final ArrayList<Thread> _threads = new ArrayList<>();
private int _previousZoom = -1;
private final int _maxNumThreads;
private static final int DEFAULT_MAX_THREADS = 20;
/**
* Regular constructor
* @param inParent manager parent to be notified of results
* @param inBuilder builder which can create the workers
*/
public TileWorkerCoordinator(TileManager inParent, TileWorkerBuilder inBuilder) {
this(inParent, inBuilder, DEFAULT_MAX_THREADS);
}
/**
* Constructor used by unit tests
* @param inParent manager parent to be notified of results
* @param inBuilder builder which can create the workers
* @param inMaxThreads maximum number of threads to allow instead of the default
*/
public TileWorkerCoordinator(TileManager inParent, TileWorkerBuilder inBuilder, int inMaxThreads) {
_parent = inParent;
_builder = inBuilder;
_maxNumThreads = inMaxThreads;
}
/**
* Entry method to trigger a tile download
* @param inDef definition of requested tile
*/
public synchronized void triggerDownload(TileDef inDef)
{
for (TileDef def : _waitingDefs) {
if (def.equals(inDef)) {
return; // already queued
}
}
if (_processingDefs.contains(inDef)) {
return; // already being processed
}
// New, so add to queue
_waitingDefs.add(inDef);
// Maybe add another worker
if (_threads.size() < _maxNumThreads)
{
Thread thread = new Thread(_builder.createWorker(this));
_threads.add(thread);
thread.start();
}
}
@Override
public synchronized TileDef getNextDefinition()
{
TileDef def = _waitingDefs.isEmpty() ? null : _waitingDefs.pop();
if (def == null) {
return null;
}
int zoom = def._zoom;
if (zoom != _previousZoom)
{
_processingDefs.clear();
_previousZoom = zoom;
}
_processingDefs.add(def);
return def;
}
@Override
public synchronized void finishedTile(TileDef inDef, TileBytes inResult)
{
if (_parent != null) {
_parent.returnTile(inDef, inResult);
}
_processingDefs.remove(inDef);
}
@Override
public void threadFinished()
{
// Go through _threads and remove the finished ones
synchronized(this)
{
ArrayList<Thread> livingThreads = new ArrayList<>();
for (Thread t : _threads)
{
if (t.isAlive() && t != Thread.currentThread()) {
livingThreads.add(t);
}
}
_threads.clear();
_threads.addAll(livingThreads);
}
}
}
|