0

Could anyone explain me why CountDownLatch on method await is hanging up although I execute countDown in separated thread? This test never ends and what is interesting ThreadPoolTaskExecutor doesn't execute code where I want to execute countDown method. I was sure that ThreadPoolTaskExecutor executes callback in different thread and CountDownLatch::await will be released.

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

...
    private ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

    @Test
    void nestedInitialization() {
        executor.initialize();
        var beanInitializer = new Initializer(executor);
   
        beanInitializer.initialize(() -> {
            new SomeBean().init();
        });

        sleep(150);
        assertEquals(0, executor.getThreadPoolExecutor().getQueue().size());
        assertTrue(beanInitializer.isInitializationDone());
    }

    class SomeBean {
        private AnotherBean anotherBean = new AnotherBean();

        void init() {
            anotherBean.init();
        }
    }

    class AnotherBean {
        private final Initializer initializer = new Initializer(executor);

        void init() {
            initializer.initialize(this::internalInit);
        }

        void internalInit() {
            sleep(100);
        }
    }

    public class Initializer {

        private ThreadPoolTaskExecutor bootstrapExecutor;

        private final CountDownLatch countDownLatch = new CountDownLatch(2);

        private Initializer(ThreadPoolTaskExecutor bootstrapExecutor) {
            this.bootstrapExecutor = bootstrapExecutor;
        }

        public void initialize(Runnable callback) {
            synchronized (this) {
                if (isNotInitialized()) {
                    countDownLatch.countDown(); // set 1 in latch
                    bootstrapExecutor.execute(() -> {
                        callback.run();
                        countDownLatch.countDown(); //  <-- this doesn't execute                   
                  });
                }
            }

            if (initializationStarted()) {
                try { 
                    countDownLatch.await();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        boolean isNotInitialized() { return countDownLatch.getCount() == 2; }

        boolean initializationStarted() { return countDownLatch.getCount() == 1; }

        boolean isInitializationDone() { return countDownLatch.getCount() == 0; }
    }

If I set any timeout in await method, callback in task executor will be executed after timeout and test passed...I can't understand this..

lolcio
  • 346
  • 5
  • 12
  • What is `ThreadPoolTaskExecutor`? – Andreas Jul 22 '21 at 18:30
  • Executor comes from spring: org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor – lolcio Jul 22 '21 at 18:31
  • 2
    Your thread pool is size 1, so when the callback is called from that thread, and you start another, that second task is now waiting on the first thread to terminate. Increase the pool size. – Andreas Jul 22 '21 at 18:47

1 Answers1

0

Problem was with size of pool. In default ThreadPoolTaskExecutor has only one thread in pool. I increased corePolSize and now his code works. Thanks Andreas!

lolcio
  • 346
  • 5
  • 12