Search code examples
javamultithreadingwaitnotifysuspend

Ensure that java thread is really suspended


I have following class:

public class PawnThread implements Runnable {

    public void start() {
        thread.start();
    }

    @Override
    public void run() {
        try {
            while (... some finish condition ...) {
                move();
                synchronized (this) {
                    while (suspendFlag) {
                        wait();
                    }
                }
            }
        } catch (InterruptedException e) {
            System.err.println(pawn.toString() + ": thread interrupted :(");
        }
    }

    void move() {
        ... some blocking actions
    }

    synchronized void suspend() {
        suspendFlag = true;
    }

    synchronized void resume() {
        suspendFlag = false;
        notify();
    }
}

Now I have a list of its objects:

private final List<PawnThread> pawnThreadList;

I defined some helper method to suspend all of them:

public void suspendAll() {
   pawnThreadList.forEach(PawnThread::suspend);
}

Now suspend() method is only about changing flag. The requirement is, that when I leave suspendAll() method, all threads should be actually paused (they cannot be in RUNNABLE state) - for now it is not a case, beacause for some of them, it may take some time to actually finish their job before pause.

I would be grateful for advice what is correct design for this soulution.

Regards


Solution

  • Make PawnThread#suspend() wait for suspension to be completed:

    public class PawnThread implements Runnable {
        private final Waiter suspender = new Waiter();
        private final Waiter suspending = new Waiter();
    
        @Override
        public void run() {
            try {
                while (...) {
                    suspending.suspend();
                    move();
                    suspending.resume();
                    suspender.await();
                }
            } catch (InterruptedException e) {
                ...
            }
        }
    
        void suspend() throws InterruptedException {
            suspender.suspend();
            suspending.await();
        }
    
        void resume() {
            suspender.resume();
        }
    }
    
    public class Waiter {
        private boolean waiting;
    
        public synchronized void await() throws InterruptedException {
            while (waiting) {
                wait();
            }
        }
    
        public synchronized void suspend() {
            waiting = true;
        }
    
        public synchronized void resume() {
            waiting = false;
            notify();
        }
    }