使用多线程提高rest服务性能

栏目: 后端 · 发布时间: 7年前

内容简介:tomcat管理线程数量有限,当达到一定请求数量时,无法继续接受请求,使用多线程的方式,可以调用一个异步线程来执行。执行逻辑如下图,tomcat就收http请求,调用一个副线程进行处理,副线程处理后,将结果返回给主线程。在副线程处理整个业务逻辑的过程中,主线程可以空闲出来,去处理其他请求。使得服务器的吞吐量可以有一个很大的提升。用同步方式和异步方式编写两个请求

tomcat管理线程数量有限,当达到一定请求数量时,无法继续接受请求,使用多线程的方式,可以调用一个异步线程来执行。

执行逻辑如下图,tomcat就收http请求,调用一个副线程进行处理,副线程处理后,将结果返回给主线程。在副线程处理整个业务逻辑的过程中,主线程可以空闲出来,去处理其他请求。使得服务器的吞吐量可以有一个很大的提升。

使用多线程提高rest服务性能

用同步方式和异步方式编写两个请求

package com.ustc.reed.controller.async;
 
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author xuanxuan
 *
 */
import java.util.concurrent.Callable;
 
@RestController
public class AsyncController {
    private static Logger logger  = LoggerFactory.getLogger(AsyncController.class);
 
    @GetMapping("/sync")
    public String sync() throws Exception{
        logger.info("主线程开始");
        Thread.sleep(1000);
 
        logger.info("主线程结束");
        return "success";
    }
 
    @GetMapping("/async")
    public Callable<String> async() throws Exception{
        logger.info("主线程开始");
        Callable<String> result = new Callable<String>() {
            @Override
            public String call() throws Exception {
                logger.info("副线程开始");
				Thread.sleep(1000);
				logger.info("副线程返回");
				return "success";
            }
        };
        logger.info("主线程结束");
        return result;
    }
}

复制代码

在浏览器中输入http://localhost:8082/reed/sync

使用多线程提高rest服务性能

在浏览器中输入http://localhost:8082/reed/async

使用多线程提高rest服务性能

在实际开发中,可能遇到接收请求和响应请求不是同一个线程的场景。如下图,此时使用callable无法满足业务需求。

可以使用 DeferredResult来处理此类业务场景。

使用多线程提高rest服务性能

以下单处理场景为例,应用服务器1的线程1收到下单请求,将下单信息发送给消息队列。应用服务器2消费消息,进行下单处理。下单完成后,将结果返回给消息队列, 应用服务器有另外一个线程2来监听消息队列,当发现有订单处理结果的消息,根据消息的结果返回HTTP响应。

线程1和线程2是完全隔离的,谁也不知道对方的存在。

限于篇幅,新建一个MockQueue,来模拟下单处理。

package com.ustc.reed.service.sync;
 
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
 * created by xuanxuan on 2019/1/6
 */
 
@Component
public class MockQueue {
    private String placeOrder;   //下单消息
 
    private String completeOrder;   //下单成功消息
 
    private Logger logger = LoggerFactory.getLogger(getClass());
 
    public String getPlaceOrder() {
        return placeOrder;
    }
 
    public void setPlaceOrder(String placeOrder) throws Exception {
        new Thread(() -> {
            logger.info("接到下单请求, " + placeOrder);
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            this.completeOrder = placeOrder;
            logger.info("下单请求处理完毕," + placeOrder);
        }).start();
    }
 
    public String getCompleteOrder() {
        return completeOrder;
    }
 
    public void setCompleteOrder(String completeOrder) {
        this.completeOrder = completeOrder;
    }
}

复制代码

每个订单号会有一个处理结果。DeferredResultHolder可以在图示的线程1和线程2之间传递DeferredResult这个对象map的key可以理解为订单号。

package com.ustc.reed.service.sync;
 
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;
 
import java.util.HashMap;
import java.util.Map;
 
/**
 * created by xuanxuan on 2019/1/6
 */
@Component
public class DeferredResultHolder {
 
    private Map<String,DeferredResult<String>> map = new HashMap<>();
 
    public Map<String, DeferredResult<String>> getMap() {
        return map;
    }
 
    public void setMap(Map<String, DeferredResult<String>> map) {
        this.map = map;
    }
}

复制代码

监听下单是否完成,完成则返回订单结果。

package com.ustc.reed.service.sync;
 
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
 
/**
 * created by xuanxuan on 2019/1/6
 */
 
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
 
    private Logger logger = LoggerFactory.getLogger(QueueListener.class);
 
    @Autowired
    private MockQueue mockQueue;
 
    @Autowired
    private DeferredResultHolder deferredResultHolder;
 
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
 
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        while (true){
 
                            if(StringUtils.isNotBlank(mockQueue.getCompleteOrder())){
                                String orderNumber = mockQueue.getCompleteOrder();
                                logger.info("返回订单结果:"+orderNumber);
                                deferredResultHolder.getMap().get(orderNumber).setResult("place order success");
                                mockQueue.setCompleteOrder(null);
                            }else {
                                try {
                                    Thread.sleep(100);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
 
                        }
                    }
                }
 
        ).start();
 
    }
}

复制代码

请求代码如下。

package com.ustc.reed.controller.async;
 
 
import com.ustc.reed.service.sync.DeferredResultHolder;
import com.ustc.reed.service.sync.MockQueue;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
/**
 * @author xuanxuan
 *
 */
import java.util.concurrent.Callable;
 
@RestController
public class AsyncController {
    private static Logger logger  = LoggerFactory.getLogger(AsyncController.class);
 
    @Autowired
    private MockQueue mockQueue;
 
    @Autowired
    private DeferredResultHolder deferredResultHolder;
 
   
    @GetMapping("/mqasync")
    public DeferredResult<String> mqasync() throws Exception{
        logger.info("主线程开始");
        String orderNumber = RandomStringUtils.randomNumeric(8);
        mockQueue.setPlaceOrder(orderNumber);
 
        DeferredResult<String> result = new DeferredResult<>();
        deferredResultHolder.getMap().put(orderNumber, result);
        return result;
 
    }
}

复制代码

在浏览器中输入http://localhost:8082/reed/mqasync ,模拟出编号为05804777的订单的处理过程,结果如下。

使用多线程提高rest服务性能

以上所述就是小编给大家介绍的《使用多线程提高rest服务性能》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Nginx Essentials

Nginx Essentials

Valery Kholodkov / Packt Publishing / 2015-7-1 / USD 34.99

About This Book Learn how to set up, configure, and operate an Nginx installation for day-to-day useExplore the vast features of Nginx to manage it like a pro, and use them successfully to run your......一起来看看 《Nginx Essentials》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具