使用多线程进行功能优化

本文探讨了在面临复杂逻辑且常规优化无法满足性能需求时,如何通过引入多线程来加速接口响应。通过代码模拟,展示了多线程在创建用户场景中的应用,以及在多线程环境下需要注意的线程安全问题。

一、应用场景

在实际工作中经常会遇到某些很复杂的逻辑,在业务和代码层面对返回速度的优化已经达到瓶颈,但时现在整个接口的返回速度还是不太令人满意,这个时候就可以考虑将部分没有强关联的业务改造成多线程,这样多个业务可以在多线程里面并发去处理,最后拿到返回值后再继续往下走,可以一定程度上加快接口的返回速度

二、代码模拟

1、首先我们模拟一下正常的场景
  • 正常的场景,比如下面的创建user就算是业务逻辑,每个方法都要耗时1秒钟
    private User createUser2(int i) throws InterruptedException {
        Thread.sleep(3000);
        User user = new User();
        user.setAge(i);
        return user;
    }
    
  • 创建10个user
    public void create() throws InterruptedException {
        System.out.println("开始");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            createUser(i);
        }
        System.out.println("结束,耗时:" + (System.currentTimeMillis()-start));
    }
    
  • 日志打印,基本上就是10秒,这个没啥好说的
开始
结束,耗时:10004
2、使用多线程去创建
  • 多线程有多种实现方式,这里我们先用实现Runable接口的方式
public class UserRun1 implements Callable<User> {
    private int age;
    public UserRun1(int age) {
        this.age = age;
    }
    @Override
    public User call() throws Exception {
        Thread.sleep(1000);
        User user = new User();
        user.setAge(age);
        return user;
    }
}
  • 使用多线程去创建
    public void create1() {
        System.out.println("多线程开始");
        long start = System.currentTimeMillis();
        ExecutorService executor = Executors.newFixedThreadPool(10) ;
        List<User> userList = new ArrayList<>(10);
        List<Future> futureList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            final int j = i;
            Future<User> submit = executor.submit(new UserRun1(j));
            futureList.add(submit);
        }
        System.out.println("futureList==" + futureList.size());
        for (Future future : futureList) {
            try {
                User user = (User) future.get();
                userList.add(user);
            } catch (Exception e) {
                log.error("e.printStackTrace()");
            }
        }
        userList.stream().map(User::getAge).sorted().forEach(age -> System.out.print(age));
        System.out.println("结束,耗时:" + (System.currentTimeMillis() - start));
        System.out.println(userList.stream().map(User::getAge).filter(item -> item != null).count());
  • 返回结果,因为我开的线程数量和实际业务数量一致,所以几乎就是单个业务的执行时间就是最后的返回时间,速度直接快了10倍
多线程开始
futureList==10
0123456789结束,耗时:1045
10

三、注意点

在多线程里面最需要注意的就是线程安全的问题了,比如在使用集合时,如果用下面这种方式去写就会有问题

  • 在多线程中使用集合去添加元素
    public void create1() throws Exception {
        System.out.println("开始");
        long start = System.currentTimeMillis();
        ExecutorService executor = Executors.newFixedThreadPool(10) ;
        List<User> userList = new ArrayList<>(10);
        List<Future> futureList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            final int j = i;
            Future submit = executor.submit(() -> {
                try {
                    createUser(userList,j);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            futureList.add(submit);
        }
        futureList.stream().forEach(item -> {
            try {
                item.get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        userList.stream().map(User::getAge).sorted().forEach(age -> System.out.print(age));
        System.out.println("结束,耗时:" + (System.currentTimeMillis() - start));
        Thread.sleep(3000);
        userList.stream().map(User::getAge).sorted().forEach(age -> System.out.print(age));
    }

    private void createUser(List<User> userList,int i) throws InterruptedException {
        Thread.sleep(1000);
        User user = new User();
        user.setAge(i);
        userList.add(user);
    }
  • 返回结果,丢了8,这是因为createUser这个方法里面使用了userList.add去添加元素,ArrayList是线程不安全的,在多线程环境下有可能刚好两个下标同时添加,所以后面覆盖了前面的,正确的做法可以将List集合换成线程安全的Vector,或者用第一种避免操作集合的方式
开始
012345679结束,耗时:1037
012345679
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值