Search code examples
javamultithreadingthread-safetythreadpooljava-threads

How to wait for one of the running threads in ExecutorService to finish to assign another task


I have loop that assign task to ExecutorService with fixed size thread, I want the main program wait for threadPool to free one of its' threads to assign another task to it.

Here is my sample code: in this sample code I want finished! be printed at end and want to use ExecutorService.

public static void main(String[] args) {
    ExecutorService ex = Executors.newFixedThreadPool(3);


    for(int i=0; i< 100; i++) {

        ex.execute(new TestThread(i)); // I want the program wait here for at least one thread to free

    }

    System.out.println("finished!");
}

private static class TestThread implements Runnable {

    private int i;
    public TestThread(int i) {
        this.i = i;
    }

    @Override
    public void run() {

        System.out.println("hi: " + i);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Solution

  • I understand you want for the thread that is submitting a job, to block in the case when there is not a free, readily available worker thread in the executor service. This can be useful to apply back-pressure.

    At the core the executor service is "simply" composed of a queue of runnables, and of a pool of worker threads.

    You can obtain this behaviour by building an executor service with a work-queue of fixed size (in your case, size one).

    In code: (note that, your caller thread will still continue after submitting the last job; it will not wait for that job to be completed)

    package stackOv;
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class BackPressure {
        public static void main(String[] args) {
            // this is the backing work queue; in this case, it is of bounded size
            ArrayBlockingQueue<Runnable> q = new ArrayBlockingQueue<>(1);
            ExecutorService ex = new ThreadPoolExecutor(3, 3, 30, TimeUnit.SECONDS, q,
                    new ThreadPoolExecutor.CallerRunsPolicy());
            for(int i=0; i< 100; i++) {
                ex.execute(new TestWork(i));
            }
            System.out.println("finished!");
        }
    
        private static class TestWork implements Runnable {
            private int i;
            public TestWork(int i) {
                this.i = i;
            }
            @Override
            public void run() {
                System.out.println("hi: " + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) { e.printStackTrace(); }
            }
        }
    }