6

The following daemon-bean is running:

public class DaemonBean extends Thread {

    private final static Logger log = LoggerFactory.getLogger(DaemonBean.class);

    {
        setDaemon(true);
        start();
    }

    @Override
    public void run() {

        for(int i=0; i<10 && !isInterrupted(); ++i) {
            log.info("Hearbeat {}", i);
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                return;
            }
        }

    }
}

It is daemon, so would terminate if singleton.

So, the following non-daemon bean is waiting for him:

public class Waitor1 extends Thread {

    private final static Logger log = LoggerFactory.getLogger(Waitor1.class);

    private Thread joinable;

    {
        setDaemon(false);
        setUncaughtExceptionHandler(new UncaughtExceptionHandler() {

            @Override
            public void uncaughtException(Thread t, Throwable e) {
                log.error("Error in thread", e);
            }
        });
    }

    public Thread getJoinable() {
        return joinable;
    }

    public void setJoinable(Thread value) {
        this.joinable = value;
        if( this.joinable != null ) {
            start();
        }
    }

    @Override
    public void run() {

        log.info("Waiting started");

        try {
            joinable.join();
        } catch (InterruptedException e) {
            log.info("Thread interrupted");
            return;
        }

        log.info("Waiting ended");

    }

}

The Spring configuration for beans is:

<bean id="daemon" class="beans.DaemonBean"/>

    <bean id="waitor" class="beans.Waitor1">
        <property name="joinable" ref="daemon"/>
    </bean>

The question is: why is it working if runned from main and not working if ran from jUnit test?

Running code is

 public static void main(String[] args) {
        new ClassPathXmlApplicationContext("/beans/Waiting1.xml");
    }

or

@Test
    public void testWaiting1() {
        new ClassPathXmlApplicationContext("/beans/Waiting1.xml");
    }

In case of main I see all hearbeats. In case of jUnit I see only heartbeat 0, then message "Waiting started" and the program is terminated as if nobody waiting for non-daemon threads here.

What can be the reason of it?

Suzan Cioc
  • 29,281
  • 63
  • 213
  • 385
  • Note: I closed that recent question https://stackoverflow.com/q/72767349/773113 as a duplicate of this one, because the same answer that answers this one can answer that one, too. However, that one is much more straightforwardly stated, without irrelevant red herrings like spring, beans, singletons, xml application contexts, and the kitchen sink. So, if you want a simple statement of the problem, look at that question, not this one. – Mike Nakis Jul 02 '22 at 13:07

1 Answers1

10

When you run your code from main it creates both beans, thus two threads - daemon and non-daemon. As long as non-daemon thread is running, your application won't exit. So it works.

It's different when run from JUnit. As soon as JUnit test method completes (and it completes immediately after the Spring context is up), JUnit assumes your tests are done. Thus it kills all your threads and basically the whole JVM.

Remember your Waitor1 bean spawns a background thread which JUnit doesn't care about. As soon as you leave @Test method JUnit will just stop everything.

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • It kills only my threads in some special way, or just terminates JVM with `System.exit()`? – Suzan Cioc Nov 25 '12 at 12:43
  • 1
    @SuzanCioc: it depends on how you run your JUnit tests (IDE, surefire, CI server) but basically it kills the JVM with `System.exit()`. – Tomasz Nurkiewicz Nov 25 '12 at 13:00
  • can this be avoided somehow? i.e. as if you'd like your test to fail if some background non-daemon thread is still running. I'd prefer JUnit framework to assert each test takes _no longer than_ say 1 min (or 2h) than to just evaporate everything all of a sudden. There is such aspect as "timely termination of a program" which is part of a program being correct. – haelix Feb 15 '19 at 21:21