Spring Boot中循环异步执行问题:如何改为同步执行?
问题背景
- 依赖版本:
- spring-boot-starter-parent 3.0.0
- 底层Spring Framework版本:<spring-framework.version>6.0.2</spring-framework.version>
该服务用于爬取网站在搜索引擎中的排名,调试时给每个网站设置了100个短语,总计200个短语,但循环会随意切换网站,最终结果数量达到380条(远超预期)。排查发现是异步执行导致的,打印的线程名称会变化,且Lombok的@Synchronized注解未起作用。
对应的代码实现:
import lombok.Synchronized; ... @Service @RequiredArgsConstructor public class RequestService { @Synchronized public void scrape() { List<SiteEntity> sites = siteRepository.findAllByActiveTrue(); System.out.println("Method: The Thread name is " + Thread.currentThread().getName()); for (SiteEntity site : sites) { System.out.println("Site: " + site.getUrl()); System.out.println("Outer: The Thread name is " + Thread.currentThread().getName()); List<PhraseEntity> phrases = phraseRepository.findAllActivePhrasesBySite(site.getId()); assertSameSite(phrases, site); final int CHUNK = 10; List<List<PhraseEntity>> phraseChunks = Lists.partition(phrases, CHUNK); for (List<PhraseEntity> chunk : phraseChunks) { System.out.println("Inner: The Thread name is " + Thread.currentThread().getName()); System.out.println(chunk.get(0).getPhrase() + " : " + chunk.get(chunk.size() - 1).getPhrase()); Document doc = sendRequest(chunk, 0); saveManager.save(doc); } } } }
问题解答
1. Spring默认是异步执行的吗?
Spring默认不是异步执行的。常规Spring Bean的方法调用都是同步的,只有显式配置异步逻辑(比如使用@Async注解、自定义TaskExecutor等)才会触发异步执行。你遇到线程名称变化的情况,大概率是sendRequest或saveManager.save内部使用了异步线程,或者scrape方法被其他异步代码调用了。
2. 如何让该循环实现同步执行?
可以从以下几个方面处理:
- 排查异步源头:检查
sendRequest和saveManager.save方法,确认内部是否存在异步逻辑,若有则改为同步实现。 - 替换Lombok的@Synchronized:Lombok的
@Synchronized默认基于当前对象加锁,若RequestService是多实例(非单例),锁会失效。可以手动使用synchronized代码块,指定全局锁对象:
同时确保@Service @RequiredArgsConstructor public class RequestService { private final Object globalLock = new Object(); public void scrape() { synchronized(globalLock) { // 原方法完整逻辑 } } }RequestService是单例(Spring默认单例,除非手动修改了作用域)。 - 保证调用链路同步:如果
scrape方法是被带有@Async注解的方法调用的,需要去掉调用方的异步配置,确保整个调用链路都是同步执行。
内容的提问来源于stack exchange,提问作者Kifsif
相关产品推荐
相关产品推荐

