Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pause/resume all threads in an ExecutorService in Java?

I submitted bunch of jobs to an executorservice in Java and I somehow want to temporarily pause all these jobs. What's the best way to do this? How can I resume? Or am I doing this completely wrong? Should I follow some other pattern for what I want to achieve (i.e. ability to pause/resume execution services)?

like image 966
pathikrit Avatar asked Mar 17 '12 09:03

pathikrit


People also ask

How do I stop all threads in ExecutorService?

In the specific case of an ExecutorService , I would vote for supporting thread interruption rather than a flag. In many frameworks, the service will be terminated with shutdownNow() .

How do you pause a thread execution?

Thread. sleep() method can be used to pause the execution of current thread for specified time in milliseconds. The argument value for milliseconds can't be negative, else it throws IllegalArgumentException .

Do we need to close ExecutorService?

When finished using an ExecutorService , you need to shut it down explicitly. From its javadoc: "An unused ExecutorService should be shut down to allow reclamation of its resources." Calling shutdown initiates a gradual and orderly shutdown.


2 Answers

To answer my own question, I found an example of a PausableThreadPoolExecutor in the javadocs of ThreadPoolExecutor itself. Here is my version using Guava's Monitors:

import com.google.common.util.concurrent.Monitor; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory;  public class PausableExecutor extends ScheduledThreadPoolExecutor {      private boolean isPaused;      private final Monitor monitor = new Monitor();     private final Monitor.Guard paused = new Monitor.Guard(monitor) {         @Override         public boolean isSatisfied() {             return isPaused;         }     };      private final Monitor.Guard notPaused = new Monitor.Guard(monitor) {         @Override         public boolean isSatisfied() {             return !isPaused;         }     };      public PausableExecutor(int corePoolSize, ThreadFactory threadFactory) {         super(corePoolSize, threadFactory);     }      protected void beforeExecute(Thread t, Runnable r) {         super.beforeExecute(t, r);         monitor.enterWhenUninterruptibly(notPaused);         try {             monitor.waitForUninterruptibly(notPaused);         } finally {             monitor.leave();         }     }      public void pause() {         monitor.enterIf(notPaused);         try {             isPaused = true;         } finally {             monitor.leave();         }     }      public void resume() {         monitor.enterIf(paused);         try {             isPaused = false;         } finally {             monitor.leave();         }     } } 
like image 184
pathikrit Avatar answered Oct 07 '22 03:10

pathikrit


I made some criticisms on your accepted answer, but they weren't very constructive... So here's my solution. I would use a class like this one and then call checkIn wherever/whenever I want pause functionality. Find it on GitHub!

import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Provides a mechanism to pause multiple threads.
 * If wish your thread to participate, then it must regularly check in with an instance of this object.
 * 
 * @author Corin Lawson <[email protected]>
 */
public class Continue {
    private boolean isPaused;
    private ReentrantLock pauseLock = new ReentrantLock();
    private Condition unpaused = pauseLock.newCondition();

    public void checkIn() throws InterruptedException {
        if (isPaused) {
            pauseLock.lock();
            try {
                while (isPaused)
                    unpaused.await();
            } finally {
                pauseLock.unlock();
            }
        }
    }

    public void checkInUntil(Date deadline) throws InterruptedException {
        if (isPaused) {
            pauseLock.lock();
            try {
                while (isPaused)
                    unpaused.awaitUntil(deadline);
            } finally {
                pauseLock.unlock();
            }
        }
    }

    public void checkIn(long nanosTimeout) throws InterruptedException {
        if (isPaused) {
            pauseLock.lock();
            try {
                while (isPaused)
                    unpaused.awaitNanos(nanosTimeout);
            } finally {
                pauseLock.unlock();
            }
        }
    }

    public void checkIn(long time, TimeUnit unit) throws InterruptedException {
        if (isPaused) {
            pauseLock.lock();
            try {
                while (isPaused)
                    unpaused.await(time, unit);
            } finally {
                pauseLock.unlock();
            }
        }
    }

    public void checkInUninterruptibly() {
        if (isPaused) {
            pauseLock.lock();
            try {
                while (isPaused)
                    unpaused.awaitUninterruptibly();
            } finally {
                pauseLock.unlock();
            }
        }
    }

    public boolean isPaused() {
        return isPaused;
    }

    public void pause() {
        pauseLock.lock();
        try {
            isPaused = true;
        } finally {
            pauseLock.unlock();
        }
    }

    public void resume() {
        pauseLock.lock();
        try {
            if (isPaused) {
                isPaused = false;
                unpaused.signalAll();
            }
        } finally {
            pauseLock.unlock();
        }
    }
}

For example:

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;

public class PausableExecutor extends ScheduledThreadPoolExecutor {
    private Continue cont;

    public PausableExecutor(int corePoolSize, ThreadFactory threadFactory, Continue c) {
        super(corePoolSize, threadFactory);
        cont = c;
    }

    protected void beforeExecute(Thread t, Runnable r) {
        cont.checkIn();
        super.beforeExecute(t, r);
    }
}

This has the added benefit that you can pause many threads with a single call to Continue's pause.

like image 40
Corin Avatar answered Oct 07 '22 01:10

Corin