0

I have 3 service classes(For now, suppose A, B, C). Each of them is a thread actually. In my requirement, each of them should have an infinite loop. But whenever I run a service class with infinite loop bean of other service classes are not created.

If there is no infinite loop, bean of each class is being created. Why is this happening?

Suppose it is Service A.

@Service
@Log4j2
public class A implements Runnable {

    private boolean isRunning = true;

    @Override
    @PostConstruct
    public void run() {
        log.debug("A Thread Started!");

        while (isRunning) {

                // just a sleep for 2 sec
        }
    }
}

Suppose it is Service B.

@Service
@Log4j2
public class B implements Runnable {

    private boolean isRunning = true;

    @Override
    @PostConstruct
    public void run() {
        log.debug("B Thread Started!");

        while (isRunning) {

                // just a sleep for 2 sec
        }
    }
}

Suppose it is Service C.

@Service
@Log4j2
public class C implements Runnable {

    private boolean isRunning = true;

    @Override
    @PostConstruct
    public void run() {
        log.debug("C Thread Started!");

        while (isRunning) {

                // just a sleep for 2 sec
        }
    }
}

And this is my Main class:

@SpringBootApplication
@Log4j2
public class Main {

    @Autowired
    public ApplicationContext context;

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @Bean
    @PostConstruct
    public void createConnection() {

        log.debug("Connecting to Server...");
        // doing some staff
    }
}

Now if I run like this, always got this log:

2020-07-14 21:21:52:129 [main] DEBUG support.DefaultListableBeanFactory:217 - Creating shared instance of singleton bean 'a'
2020-07-14 21:21:52:130 [main] DEBUG service.ProcessorService:27 - A Thread Started!

If I put any log in while loop of class A, then only those logs are shown.

If I comment on the loop portion of the class A and keep the class like this:

@Service
@Log4j2
public class A implements Runnable {

    private boolean isRunning = true;

    @Override
    @PostConstruct
    public void run() {
        log.debug("A Thread Started!");

       /* while (isRunning) {

                // just a sleep for 2 sec
        }*/
    }
}

then got this in log:

2020-07-14 21:30:31:198 [main] DEBUG support.DefaultListableBeanFactory:217 - Creating shared instance of singleton bean 'a'
2020-07-14 21:30:31:199 [main] DEBUG service.ProcessorService:27 - A Thread Started!
2020-07-14 21:30:31:199 [main] DEBUG support.DefaultListableBeanFactory:217 - Creating shared instance of singleton bean 'b'
2020-07-14 21:30:31:199 [main] DEBUG service.ReceivingProcessingService:46 - B Thread Started!

If I comment on the loop portion of class B as well then only got each service class running. Can't understand the reason. Any help will be appreciated.

Mukit09
  • 2,956
  • 3
  • 24
  • 44

2 Answers2

0

The PostConstruct method is never ending in your case so spring is unable to proceed further. Ideally, you should create a separate class MyRunnable which implements Runnable and override its run method with your logic and start a new thread in post construct method as below:

@PostConstruct
public void init() {
  log.debug("Starting thread!");
  Thread myThread = new Thread(new MyRunnable());
  myThread.start();
}

You can now remove the "implements Runnable" from your service class

  • But by this, if I autowire any reference in the service classes, then spring will not create that bean. right? As in this, spring boot is not running the thread. I am doing it myself. – Mukit09 Jul 14 '20 at 16:15
  • The code to run the thread will be executed by Spring boot as it is in PostContruct method. When your application starts, it will invoke the init() method which will in turn start the thread. – Shailesh Jain Jul 14 '20 at 16:18
  • So by this init() how will I run 3 different thread? You want to say I can write my logic in MyRunnable1, MyRunnale2 and MyRunnable3 classes? And will remove service classes? – Mukit09 Jul 14 '20 at 16:23
  • Right, either create 3 runnables if the logic is different or you can use same runnable if logic is same and in each service start a new thread in PostConstruct init() method with runnable of your choice. Don't remove service classes, you still need them to invoke your PostConstruct methods, just don't implement Runnable interface in those services now. – Shailesh Jain Jul 14 '20 at 16:27
0

That is how I changed my code. I used ThreadPoolExecutor now.

@Configuration
@Log4j2
public class AppConfiguration {
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        log.debug("Config called of taskExecutor...");
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setCorePoolSize(3);
        pool.setMaxPoolSize(3);
        pool.setWaitForTasksToCompleteOnShutdown(true);
        pool.initialize();
        return pool;
    }
}

Then run the services like this:

private void runServices() {
    ThreadPoolTaskExecutor executor = (ThreadPoolTaskExecutor) context.getBean("taskExecutor");

    A a = context.getBean(A.class);
    executor.execute(a);

    B b = context.getBean(B.class);
    executor.execute(b);

    C c = context.getBean(C.class);
    executor.execute(c);

    log.debug("Active Executor: " + executor.getActiveCount());
}

And the service classes are same, just removed the PostConstruct annotation.

it is Service A.

@Service
@Log4j2
public class A implements Runnable {

    private boolean isRunning = true;

    @Override
    public void run() {
        log.debug("A Thread Started!");

        while (isRunning) {

                // just a sleep for 2 sec
        }
    }
}

it is Service B.

@Service
@Log4j2
public class B implements Runnable {

    private boolean isRunning = true;

    @Override
    public void run() {
        log.debug("B Thread Started!");

        while (isRunning) {

                // just a sleep for 2 sec
        }
    }
}

it is Service C.

@Service
@Log4j2
public class C implements Runnable {

    private boolean isRunning = true;

    @Override
    public void run() {
        log.debug("C Thread Started!");

        while (isRunning) {

                // just a sleep for 2 sec
        }
    }
}

Now everything is running fine.

Mukit09
  • 2,956
  • 3
  • 24
  • 44