美文网首页
18-Springboot支持多线程

18-Springboot支持多线程

作者: wshsdm | 来源:发表于2022-05-16 14:19 被阅读0次

    1 创建maven项目,修改pom.xml加入依赖库

        <dependencies>    
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.5.4</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.4.2</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.20</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>8</source>
                        <target>8</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    

    2 创建资源配置文件resources/application.yml

    server:
      port: 7100
    #配置RestTemplate部分
    http:
      #最大连接数
      maxTotal: 100
      #并发数
      defaultMaxPerRoute: 20
      #创建连接的最长时间
      connectTimeout: 1000
      #从连接池中获取到连接的最长时间
      connectionRequestTimeout: 500
      #数据传输的最长时间
      socketTimeout: 10000
      #提交请求前测试连接是否可用
      staleConnectionCheckEnabled: true
      #可用空闲连接过期时间,重用空闲连接时会先检查是否空闲时间超过这个时间,如果超过,释放socket重新建立
      validateAfterInactivity: 3000000
    

    3 创建RestTemplate配置类

    package com.demo.cfg;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.config.Registry;
    import org.apache.http.config.RegistryBuilder;
    import org.apache.http.conn.socket.ConnectionSocketFactory;
    import org.apache.http.conn.socket.PlainConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.client.ClientHttpRequestFactory;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.web.client.RestTemplate;
    
    /**
     * 代码描述: RestTemplate配置类
     * @author wujianping
     * @since 2022/4/30 17:02
     */
    @Configuration
    public class RestTemplateConfig {
        @Value("${http.maxTotal}")
        private Integer maxTotal;
    
        @Value("${http.defaultMaxPerRoute}")
        private Integer defaultMaxPerRoute;
    
        @Value("${http.connectTimeout}")
        private Integer connectTimeout;
    
        @Value("${http.connectionRequestTimeout}")
        private Integer connectionRequestTimeout;
    
        @Value("${http.socketTimeout}")
        private Integer socketTimeout;
    
        @Value("${http.staleConnectionCheckEnabled}")
        private boolean staleConnectionCheckEnabled;
    
        @Value("${http.validateAfterInactivity}")
        private Integer validateAfterInactivity;
    
    
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate(httpRequestFactory());
        }
    
        @Bean
        public ClientHttpRequestFactory httpRequestFactory() {
            return new HttpComponentsClientHttpRequestFactory(httpClient());
        }
    
        @Bean
        public HttpClient httpClient() {
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", SSLConnectionSocketFactory.getSocketFactory())
                    .build();
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
            connectionManager.setMaxTotal(maxTotal); // 最大连接数
            connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);    //单个路由最大连接数
            connectionManager.setValidateAfterInactivity(validateAfterInactivity); // 最大空间时间
            RequestConfig requestConfig = RequestConfig.custom()
                    .setSocketTimeout(socketTimeout)        //服务器返回数据(response)的时间,超过抛出read timeout
                    .setConnectTimeout(connectTimeout)      //连接上服务器(握手成功)的时间,超出抛出connect timeout
                    .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled) // 提交前检测是否可用
                    .setConnectionRequestTimeout(connectionRequestTimeout)//从连接池中获取连接的超时时间,超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
                    .build();
            return HttpClientBuilder.create()
                    .setDefaultRequestConfig(requestConfig)
                    .setConnectionManager(connectionManager)
                    .build();
        }
    }
    

    3 创建异步任务配置类

    package com.demo.cfg;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    import java.util.concurrent.Executor;
    
    /**
     * 代码描述: 异步任务配置类
     *
     * @author wujianping
     * @since 2022/5/16 13:52
     */
    @Configuration
    // 启用异步任务
    @EnableAsync
    public class AsyncConfiguration {
        /**
         * 声明一个线程池(并指定线程池的名字)
         * @param
         * @return Executor
         */
        @Bean("taskExecutor")
        public Executor asyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            //核心线程数3:线程池创建时候初始化的线程数
            executor.setCorePoolSize(3);
            //最大线程数5:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
            executor.setMaxPoolSize(5);
            //缓冲队列500:用来缓冲执行任务的队列
            executor.setQueueCapacity(500);
            //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
            executor.setKeepAliveSeconds(60);
            //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
            executor.setThreadNamePrefix("DailyAsync-");
            executor.initialize();
            return executor;
        }
    }
    

    4 创建业务接口

    package com.demo.service;
    
    import java.util.concurrent.CompletableFuture;
    
    /**
     * 代码描述: 业务接口
     * @author wujianping
     * @since 2022/5/16 13:39
     */
    public interface UserService{
        /**
         * 执行异步任务
         */
        CompletableFuture<String> findUser(String user) throws InterruptedException;
    }
    

    5 创建业务实现类

    package com.demo.service.impl;
    
    import com.demo.service.UserService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    import javax.annotation.Resource;
    import java.util.concurrent.CompletableFuture;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 代码描述: 业务实现类
     *
     * @author wujianping
     * @since 2022/5/16 13:39
     */
    @Slf4j
    @Service
    public class UserServiceImpl implements UserService {
        @Resource
        private RestTemplate restTemplate;
    
        // 这里进行标注为异步任务,在执行此方法的时候,会单独开启线程来执行(并指定线程池的名字)
        @Async("taskExecutor")
        public CompletableFuture<String> findUser(String user) throws InterruptedException {
            log.info("Looking up " + user);
            String url = String.format("https://api.github.com/users/%s", user);
            String results = restTemplate.getForObject(url, String.class);
            // Artificial delay of 3s for demonstration purposes
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println("sleep...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return CompletableFuture.completedFuture(results);
        }
    }
    

    6 创建控制器调用业务方法

    package com.demo.controller;
    
    import com.demo.po.Student;
    import com.demo.service.UserService;
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.CompletableFuture;
    
    /**
     *
     * @author wujianping
     * @since 2022/5/12 9:53
     */
    @Slf4j
    @CrossOrigin(origins = "*")
    @RestController
    public class StudentController {
        @Autowired
        private UserService userService;
        @SneakyThrows
        @GetMapping("/mul")
        public String mul(){
            // Start the clock
            long start = System.currentTimeMillis();
            // Kick of multiple, asynchronous lookups
            CompletableFuture<String> page1 = userService.findUser("PivotalSoftware");
            CompletableFuture<String> page2 = userService.findUser("CloudFoundry");
            CompletableFuture<String> page3 = userService.findUser("Spring-Projects");
    
            // Wait until they are all done
            //join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行
            CompletableFuture.allOf(page1, page2, page3).join();
    
            // Print results, including elapsed time
            float exc = (float)(System.currentTimeMillis() - start)/1000;
            log.info("Elapsed time: " + exc + " seconds");
            log.info("--> " + page1.get());
            log.info("--> " + page2.get());
            log.info("--> " + page3.get());
            return "ok";
        }
    }
    

    相关文章

      网友评论

          本文标题:18-Springboot支持多线程

          本文链接:https://www.haomeiwen.com/subject/nfqwurtx.html