After playing around with different approaches I was able to create a working solution thanks to this article: Using wait/notify vs Thread.sleep() in Java
Basically each Task(Process1Thread) inherits its own monitor/lock from parent class that extends Thread class. The run() method in Task classes runs in an infinite loop, in a synchronized block(with its monitor/lock) and at the end of each cycle notifies the MainThread and than waits, locking it self until MainThread notifies them to continue with the loop.
MainThread has each task in a HashMap as a key and time to wait as a value. It also runs in an infinite loop in a synchronized block with a monitor/lock for the task its currently running, checking each cycle for the shortest wait time from the HashMap and than running the task with the shortest wait time and waiting for the task to notify it to continue. Each time the task sends notify/wait on the monitor/lock, the MainThread continues the loop..
Anyway for anyone having a similar issue, here is the code:
AThread class:
public abstract class AThread extends Thread {
protected boolean firstRun = true;
private final Object monitor = new Object();
protected final Object getMonitor() {
return monitor;
}
}
DelegateThread class:
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class DelegateThread {
public static boolean running = true;
private static Map<AThread, Integer> map;
private static Random rand = new Random();
public static class Process1Thread extends AThread {
@Override
public void run() {
while (running) {
synchronized (getMonitor()) {
try {
int time = map.get(this);
for (int i = 0; i < time; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(i + 1 + "-");
}
System.out.println("Finished task [" + this + "]; Time: " + time);
time = randInt(4, 10);
System.out.println("new Time for " + this + " is: " + time);
map.put(this, time);
getMonitor().notify();
getMonitor().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static class Process2Thread extends AThread {... the same as Process1Thread, just different name}
public static class Process3Thread extends AThread {... the same as Process1Thread, just different name}
public static class MainThread extends Thread {
public void run() {
System.out.println("-= Start =-");
Map.Entry<AThread, Integer> min;
while (running) {
try {
min = getMin();
synchronized (min.getKey().getMonitor()) {
System.out.println("--------------------------------------------------");
System.out.println("Sleeping " + min.getKey() + " for: " + min.getValue());
Thread.sleep(min.getValue() * 1000);
if (min.getKey().firstRun) {
min.getKey().start();
min.getKey().firstRun = false;
}
min.getKey().getMonitor().notify();
min.getKey().getMonitor().wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(" -= END =- ");
}
public Map.Entry<AThread, Integer> getMin() {
Map.Entry<AThread, Integer> min = null;
for (Map.Entry<AThread, Integer> entry : map.entrySet()) {
if (min == null || min.getValue() > entry.getValue()) {
min = entry;
}
}
return min;
}
}
public static void main(String[] args) {
MainThread mainThread = new MainThread();
Process1Thread process1Thread = new Process1Thread();
Process2Thread process2Thread = new Process2Thread();
Process3Thread process3Thread = new Process3Thread();
map = new HashMap<>(3);
map.put(process1Thread, 0);
map.put(process2Thread, 1);
map.put(process3Thread, 2);
mainThread.start();
}
public static int randInt(int min, int max) {
return rand.nextInt((max - min) + 1) + min;
}
}
Runnable
doesn't mean it runs on a separate thread. You would neednew Thread().start()
for that. Also, I'm not sure what your end-game is, but it sounds like ExecutorService may be helpful - it's good for passing-off operations to another thread. – pathfindereliteMap
if all you wish to do is iterate over it as if it was aList
? Also, as @pathfinderelite pointed out, threads need to be started usingstart
and notrun
– CKing