0%

Spring Boot-多线程

一般我们使用多线程的方法是,继承Thread类,实现Runnable接口等方式,但在Spring中这样使用可能会导致bean无法注入等问题,所以在spring 3之后,就提供了@Async注解,很好地实现了多线程。

背景

使用get方法调用api,需要尽可能多得获取数据,插入数据库。

  • 未使用多线程,每获取1000条数据需要4分钟
  • 使用多线程后,每获取1000条数据需要16秒

配置

需要异步的方法加上@Async注解,类加上@Scope(“prototype”)、@Service,将此多例注入容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Scope("prototype")
@Service
@Slf4j
public class MyAsync {
@Autowired
private Call call;

@Async
public void run(int k){
long startTime = System.currentTimeMillis();
List<User> list = new ArrayList<>();
try {
for(int i = k; i < k + 100; i++){
User user = call.getUser(i);
if(user != null){
list.add(user);
}
}
}
catch (Exception e){
e.printStackTrace();
}
finally {
call.saveAll(list);
long endTime = System.currentTimeMillis();
log.info("程序开始值:" + k + "程序执行时间:" + (endTime-startTime)/1000 + "s");
}
}
}

每个线程获取100条数据

运行

junit单元测试不支持多线程,执行test方法,test方法执行结束后会无视其他线程直接结束程序。所以需要在spring boot的启动类中运行多线程。加上@EnableAsync注解,使多线程可用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@EnableAsync
@SpringBootApplication
public class Application {

public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(Application.class, args);
MyAsync m = applicationContext.getBean(MyAsync.class);
int k = 1;
for(int i = k ; i < k + 1000 ; i += 100){
m.run(i);
}
}

}

从k开始,开启10个线程,获取1000条数据,

注意

大量获取数据可能会封ip,推荐使用代理ip获取数据

1
2
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ip, port));
HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy);