The service variable is not read in a method running in another thread

Issue

The Spring application In the service spins an endless cycle

@Service
public class MyService {
    public boolean isStart = false;

    @Async("threadPoolTaskExecutor")
    public void sending() {        
        while (isStartService) {
        ...
        }     
    }
}

@Service
public class OneService {
  @Autowired  
  private final MyService myService;
  
  public void start(boolean isStautus) {
    myService.isStart = true;
    myService.sending();
 }
}

In another service, I set the value of the variable is Start Service = true. While there was no Async annotation on this method, everything worked. But as soon as it was added, and it began to run in a separate thread, the isStartService variable inside this method is now always = false. The loop is never executed. How do I correctly pass the value of this variable inside this stream. I.e. at first it should be true, and after some time its value is passed false and thus the method stops working.

I tried to make the isStart variable as volatile. It didn’t help

Solution

The problem is that @Async triggers the creation of a proxy, so when you mutate the variable directly, the proxy doesn’t intercept that call.

Create a setter for the isStart property and it’ll work.

This application works as expected with the setter. You should make the field volatile so that it always fetches the updated value of the field.

@SpringBootApplication
@EnableAsync
public class SO72313483 {

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

    private final static Logger logger = LoggerFactory.getLogger(SO72313483.class);

    @Service
    public static class MyService {
        private volatile boolean isStartService = false;

        @Async("taskExecutor")
        public void sending() throws Exception {
            while (isStartService) {
                logger.info("Here");
                Thread.sleep(5000);
            }
        }

        public void setStartService(boolean startService) {
            isStartService = startService;
        }
    }

    @Service
    public static class OneService {

        @Autowired
        private MyService myService;

        public void start(boolean isStatus) throws Exception{
            myService.setStartService(true);
            myService.sending();
        }
    }

    @Autowired
    OneService oneService;

    @Bean
    ApplicationRunner runnerSO72313483() {
        return args -> oneService.start(true);
    }

}

Answered By – Tomaz Fernandes

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published