多线程 实现高效多借口调用

正常情况下我们调用多借口,都会顺序调用,也就是串行,如果借口直接没有任何关系,而串行执行消耗的时间,就是各个借口直接调用的总和。而jdk其实给我们提供有返回值类型线程,可以解决这个问题。

测试基类:用于统计执行时间

import org.apache.commons.lang.StringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;

import com.ms.cloud.common.util.frame.SpObserver;

@RunWith(SpringRunner.class)
public class BaseTest {

    
    private Long starttime;
    @Rule
    public TestName junitClass= new TestName();
    @Before
    public void before() {
        starttime = System.currentTimeMillis();
        setDataSource();
        System.out.println(junitClass.getMethodName() + "....................start....................");
    }
    @After
    public void after() {
        double usedtime = (System.currentTimeMillis() - starttime) / 1000.0;
        System.out.println("耗时  " + usedtime + " ms");
        System.out.println(junitClass.getMethodName() + "....................end....................");
    }

    protected void setDataSource() {
        this.setDataSource(null, null);
    }
    protected void setDataSource(String city, String sourceType) {
        if (StringUtils.isEmpty(city)) {
            city = "sz";
        }
        if (StringUtils.isEmpty(sourceType)) {
            sourceType = "PC";
        }
        SpObserver.putSoruce(sourceType);
        SpObserver.putSp(city);
    }
    
}

工具类,模拟用户调用多借口。每个接口消耗几秒钟。。

import java.util.concurrent.TimeUnit;

public class UserUtils {

    public static String getHead(String uid) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        return ""+uid+"】的头";
    }
    public static String getFace(String uid)throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
        return ""+uid+"】的脸";
    }
    public static String getFoot(String uid) throws InterruptedException {
        TimeUnit.SECONDS.sleep(7);
        return ""+uid+"】的脚";
    }
}

正常情况下我们执行程序如此:

普通人:

import org.junit.Test;

public class MyGodTest extends BaseTest {

    @Test
    public void testDo() throws InterruptedException {
        String uid = "路人甲";
        StringBuffer sb = new StringBuffer();
        sb.append(UserUtils.getHead(uid)).append("
");
        sb.append(UserUtils.getFace(uid)).append("
");
        sb.append(UserUtils.getFoot(uid)).append("
");
        System.out.println("信息为:
" + sb.toString());
    }
}

直接串联:执行结果耗时14+s

testDo....................start....................
信息为:
【路人甲】的头
【路人甲】的脸
【路人甲】的脚

耗时 14.016 ms testDo....................end....................

老程序员:

开启多线程,异步模式。用线程池与不用都可以。。让线程跑起来就行

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import org.junit.Test;

/**
 * @desc 采用线程方式 
 * @author 陈惟鲜 chenweixian
 * @date 2020年7月23日 下午1:00:23
 *
 */
public class MyGodThreadTest extends BaseTest {

    /**用线程执行
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @Test
    public void testDo() throws InterruptedException, ExecutionException {
        String uid = "路人甲";
        StringBuffer sb = new StringBuffer();
        Callable<String> headCallable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return UserUtils.getHead(uid);
            }
        };
        
        Callable<String> faceCallable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return UserUtils.getFace(uid);
            }
        };
        
        Callable<String> footCallable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return UserUtils.getFoot(uid);
            }
        };
        // 
        FutureTask<String> headFutureTask = new FutureTask<>(headCallable);
        FutureTask<String> faceFutureTask = new FutureTask<>(faceCallable);
        FutureTask<String> footFutureTask = new FutureTask<>(footCallable);
        
        // 执行方法,线程异步执行
        new Thread(headFutureTask).start();
        new Thread(faceFutureTask).start();
        new Thread(footFutureTask).start();
        
        sb.append(headFutureTask.get()).append("
");
        sb.append(faceFutureTask.get()).append("
");
        sb.append(footFutureTask.get()).append("
");
        System.out.println("信息为:
" + sb.toString());
    }
    
    /**用线程池执行
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @Test
    public void testPoolDo() throws InterruptedException, ExecutionException {
        String uid = "路人甲";
        StringBuffer sb = new StringBuffer();
        Callable<String> headCallable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return UserUtils.getHead(uid);
            }
        };
        
        Callable<String> faceCallable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return UserUtils.getFace(uid);
            }
        };
        
        Callable<String> footCallable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return UserUtils.getFoot(uid);
            }
        };
        // 
        FutureTask<String> headFutureTask = new FutureTask<>(headCallable);
        FutureTask<String> faceFutureTask = new FutureTask<>(faceCallable);
        FutureTask<String> footFutureTask = new FutureTask<>(footCallable);
        
        // 执行方法,线程异步执行
        ExecutorService executor = Executors.newCachedThreadPool();
        executor.submit(headFutureTask);
        executor.submit(faceFutureTask);
        executor.submit(footFutureTask);
        executor.shutdown();
        
        sb.append(headFutureTask.get()).append("
");
        sb.append(faceFutureTask.get()).append("
");
        sb.append(footFutureTask.get()).append("
");
        System.out.println("线程池信息为:
" + sb.toString());
    }
}

执行结果:7+s

testPoolDo....................start....................
线程池信息为:
【路人甲】的头
【路人甲】的脸
【路人甲】的脚

耗时  7.02 ms
testPoolDo....................end....................

总结:

多学多看,多实践,对工作有帮助。

核心部分如下

Callable<String> footCallable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return UserUtils.getFoot(uid); == 业务处理
            }
        };
FutureTask<String> headFutureTask = new FutureTask<>(headCallable);
new Thread(faceFutureTask).start(); ==执行程序
footFutureTask.get() ==得到响应结果



原文地址:https://www.cnblogs.com/a393060727/p/13365813.html