javaspringspring-async

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


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);
        }
    
    }