0
votes

I am trying to implement a model where I have a main thread that delegates work to worker threads. These worker thread run in an infinite loop, doing actions periodically, and after each action they are waiting(sleeping) till they get notified to continue by the main thread. They also send an information how long to wait till the next action to the main thread. Main thread decides by the shortest amount of wait time who runs next at what time and in the meanwhile they sleep.

I have designed how I imagine it could work, but it gets stuck after I run the first thread. First thing that comes to my mind is bad design, but still I believe this should also work. Does anyone have a suggestion how to make it work? Thanks a lot

Edited: see answer below..

1
I don't see any multi-threading here. Extending Runnable doesn't mean it runs on a separate thread. You would need new 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.pathfinderelite
That's a lot of code to review. That being said, why do you use a Map if all you wish to do is iterate over it as if it was a List? Also, as @pathfinderelite pointed out, threads need to be started using start and not runCKing
@ChetanKinger Well the map key is a thread, and value is wait time. Also I wanted to change the wait time by the worker threads so I access the map by (this) since its from the worker thread it self. I believe it can be done better ofc, but this is first try to implement it. Also sorry for the wall of text..matty
@pathfinderelite well I didn't know how to be able to have three separate infinite loops without multithreading.. those loops iterate through tasks and wait till they are finished, in the meanwhile other worker continues.. but thanks for that Runnable/new Thread tip, might help quite a bitmatty

1 Answers

0
votes

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;
    }
}