欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我微信「java_front」一起交流学习
声明A服务提供五个方法:
public class BizParamDTO {
private String field;
}
public interface AService {
public String a1(BizParamDTO param) throws Exception;
public String a2(BizParamDTO param) throws Exception;
public String a3(BizParamDTO param) throws Exception;
public String a4(BizParamDTO param) throws Exception;
public String a5(BizParamDTO param) throws Exception;
}
a1-a4休眠100毫秒,a5休眠600毫秒:
@Service
public class AServiceImpl implements AService {
@Override
public String a1(BizParamDTO param) throws Exception {
System.out.println(Thread.currentThread().getName() + ",a1 param=" + param);
TimeUnit.MILLISECONDS.sleep(100);
return param.getField();
}
@Override
public String a2(BizParamDTO param) throws Exception {
System.out.println(Thread.currentThread().getName() + ",a2 param=" + param);
TimeUnit.MILLISECONDS.sleep(100);
return param.getField();
}
@Override
public String a3(BizParamDTO param) throws Exception {
System.out.println(Thread.currentThread().getName() + ",a3 param=" + param);
TimeUnit.MILLISECONDS.sleep(100);
return param.getField();
}
@Override
public String a4(BizParamDTO param) throws Exception {
System.out.println(Thread.currentThread().getName() + ",a4 param=" + param);
TimeUnit.MILLISECONDS.sleep(100);
return param.getField();
}
@Override
public String a5(BizParamDTO param) throws Exception {
System.out.println(Thread.currentThread().getName() + ",a5 param=" + param);
TimeUnit.MILLISECONDS.sleep(600);
return param.getField();
}
}
B服务同步调用A服务五个方法:
public interface BService {
public void b(BizParamDTO param) throws Exception;
}
@Service
public class BServiceImpl implements BService {
@Resource
private AService aservice;
@Override
public void b(BizParamDTO param) throws Exception {
StopWatch stopWatch = new StopWatch();
stopWatch.start("taskB");
String r1 = aservice.a1(param);
String r2 = aservice.a2(param);
String r3 = aservice.a3(param);
String r4 = aservice.a4(param);
String r5 = aservice.a5(param);
List<String> result = Arrays.asList(r1, r2, r3, r4, r5);
stopWatch.stop();
System.out.println("b1-costTime=" + stopWatch.getTotalTimeMillis() + "ms");
}
}
C服务通过异步调用A服务:
public interface CService {
public void c(BizParamDTO param) throws Exception;
}
@Service
public class CServiceImpl implements CService {
private final static Integer TYPE = TypeEnum.CPU.getCode();
@Resource
private AService aservice;
@Override
public void c(BizParamDTO param) throws Exception {
StopWatch stopWatch = new StopWatch();
stopWatch.start("taskC");
Future<String> f1 = MyThreadFactory.get(TYPE).submit(new Callable<String>() {
@Override
public String call() throws Exception {
StopWatch s = new StopWatch();
s.start();
String result = aservice.a1(param);
s.stop();
System.out.println("a1-costTime=" + s.getTotalTimeMillis() + "ms");
return result;
}
});
Future<String> f2 = MyThreadFactory.get(TYPE).submit(new Callable<String>() {
@Override
public String call() throws Exception {
StopWatch s = new StopWatch();
s.start();
String result = aservice.a2(param);
s.stop();
System.out.println("a2-costTime=" + s.getTotalTimeMillis() + "ms");
return result;
}
});
Future<String> f3 = MyThreadFactory.get(TYPE).submit(new Callable<String>() {
@Override
public String call() throws Exception {
StopWatch s = new StopWatch();
s.start();
String result = aservice.a3(param);
s.stop();
System.out.println("a3-costTime=" + s.getTotalTimeMillis() + "ms");
return result;
}
});
Future<String> f4 = MyThreadFactory.get(TYPE).submit(new Callable<String>() {
@Override
public String call() throws Exception {
StopWatch s = new StopWatch();
s.start();
String result = aservice.a4(param);
s.stop();
System.out.println("a4-costTime=" + s.getTotalTimeMillis() + "ms");
return result;
}
});
Future<String> f5 = MyThreadFactory.get(TYPE).submit(new Callable<String>() {
@Override
public String call() throws Exception {
StopWatch s = new StopWatch();
s.start();
String result = aservice.a5(param);
s.stop();
System.out.println("a5-costTime=" + s.getTotalTimeMillis() + "ms");
return result;
}
});
// 等待结果
StopWatch watch = new StopWatch("waitWatch");
watch.start("f1.get()");
String r1 = f1.get();
watch.stop();
watch.start("f2.get()");
String r2 = f2.get();
watch.stop();
watch.start("f3.get()");
String r3 = f3.get();
watch.stop();
watch.start("f4.get()");
String r4 = f4.get();
watch.stop();
watch.start("f5.get()");
String r5 = f5.get();
watch.stop();
// 输出结果
List<String> result = Arrays.asList(r1, r2, r3, r4, r5);
stopWatch.stop();
System.out.println("c1-costTime=" + stopWatch.getTotalTimeMillis() + "ms,costTimeDetail=" + watch.prettyPrint());
}
}
我们把线程池划分为两种类型:
public enum TypeEnum {
IO(1, "IO密集"),
CPU(2, "CPU密集")
}
CPU密集型线程数:CPU数量+1
IO密集型线程数:CPU数量除以(1-阻塞系数0.9)
public class MyThreadFactory {
/** 线程执行器 **/
private static volatile ThreadPoolExecutor executor;
/** 队列存放任务数 **/
private static int QUEUE_MAX_SIZE = 1000;
/** 线程存活时间 **/
private static long KEEP_ALIVE_TIME = 1000;
public static ThreadPoolExecutor get(int type) {
if (executor == null) {
synchronized (ThreadFactory.class) {
if (executor == null) {
int cpuNum = Runtime.getRuntime().availableProcessors();
int coreSize = cpuNum;
if (type == TypeEnum.CPU.getCode()) {
coreSize = cpuNum + 1;
} else if (type == TypeEnum.IO.getCode()) {
coreSize = cpuNum * 10;
}
int maxSize = coreSize;
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(QUEUE_MAX_SIZE);
executor = new ThreadPoolExecutor(coreSize, maxSize, KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS, queue);
}
}
}
return executor;
}
/**
* 本机8核16处理器
*/
public static void main(String[] args) {
int cpuNum = Runtime.getRuntime().availableProcessors(); // 16
System.out.println("cpuNum=" + cpuNum);
}
}
@RestController
@RequestMapping("/test")
public class BizController {
@Resource
private BService bservice;
@Resource
private CService cservice;
@PostMapping("/biz1")
public boolean biz1(@RequestBody BizParamDTO param) throws Exception {
bservice.b(param);
return true;
}
@PostMapping("/biz2")
public boolean biz2(@RequestBody BizParamDTO param) throws Exception {
cservice.c(param);
return true;
}
}
postman访问端点biz1,此时选择CPU密集型线程池:
http://localhost:8080/javafront/test/biz1
{
"field": "a"
}
耗时日志如下:
b1-costTime=1036ms
耗时计算公式:
100ms(a1) + 100ms(a2) + 100ms(a3) + 100ms(a4) + 500ms(a5) = 1000ms
postman访问端点biz2:
http://localhost:8080/javafront/test/biz2
{
"field": "a"
}
耗时日志如下:
a2-costTime=104ms
a4-costTime=104ms
a1-costTime=104ms
a3-costTime=104ms
a5-costTime=602ms
c1-costTime=604ms,costTimeDetail=StopWatch 'waitWatch': running time = 604224000 ns
---------------------------------------------
ns % Task name
---------------------------------------------
105678000 017% f1.get()
000001800 000% f2.get()
000048100 000% f3.get()
000000400 000% f4.get()
498495700 083% f5.get()
本次耗时日志稍显复杂,可以把日志分为执行部分和等待部分:
a2-costTime=104ms
a4-costTime=104ms
a1-costTime=104ms
a3-costTime=104ms
a5-costTime=602ms
c1-costTime=604ms,costTimeDetail=StopWatch 'waitWatch': running time = 604224000 ns
---------------------------------------------
ns % Task name
---------------------------------------------
105678000 017% f1.get()
000001800 000% f2.get()
000048100 000% f3.get()
000000400 000% f4.get()
498495700 083% f5.get()
现在分析异步在50线程时耗时日志,分析耗时主要发生执行部分,还是发生在等待部分。
a5-costTime=601ms
a1-costTime=108ms
a4-costTime=108ms
a2-costTime=108ms
a3-costTime=108ms
c1-costTime=602ms,costTimeDetail=StopWatch 'waitWatch': running time = 602183001 ns
---------------------------------------------
ns % Task name
---------------------------------------------
105515000 018% f1.get()
000000200 000% f2.get()
000777201 000% f3.get()
000101800 000% f4.get()
495788800 082% f5.get()
a1-costTime=110ms
a2-costTime=109ms
a3-costTime=110ms
a5-costTime=613ms
a4-costTime=110ms
c1-costTime=3080ms,costTimeDetail=StopWatch 'waitWatch': running time = 3080277201 ns
---------------------------------------------
ns % Task name
---------------------------------------------
2528728000 082% f1.get()
016059001 001% f2.get()
031992801 001% f3.get()
000046199 000% f4.get()
503451200 016% f5.get()
执行部分
等待部分
分析小结
本文第一编写了同步和异步代码,并在代码中输出了耗时日志。第二分析单次执行同步和异步的表现,异步优于同步。第三结合不同线程池配置进行压测,如果线程池选择不合适,异步执行性能不如同步,所以要配置合适线程数。
欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我微信「java_front」一起交流学习