@Slf4j
public class PerformanceTool {
private final ThreadPoolExecutor executor;
public PerformanceTool(int numOfThreads) {
this.executor = new ThreadPoolExecutor(numOfThreads, numOfThreads, 1, TimeUnit.MINUTES,
new LinkedBlockingDeque<>(10000), new PerformanceThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
}
public CompletableFuture<Result> run(String url, int nums){
return CompletableFuture.supplyAsync(() -> {
Result result = null;
CountDownLatch latch = new CountDownLatch(nums);
List<Integer> responseTimeList = Lists.newArrayList();
int loop = 0;
while (loop < nums) {
executor.submit(() -> {
HttpUriRequest request = new HttpGet(url);
try {
long start = System.currentTimeMillis();
int codeResult = HttpClients.createDefault()
.execute(request)
.getStatusLine()
.getStatusCode();
long end = System.currentTimeMillis();
responseTimeList.add((int) (end-start));
} catch (IOException e) {
log.error("http has error !",e);
}
latch.countDown();
});
++loop;
}
try {
latch.await();
} catch (InterruptedException e) {
log.error("Interrupted has error !",e);
}
return new Result(responseTimeList);
});
}
public static void main(String[] args) {
PerformanceTool performanceTool = new PerformanceTool(10);
CompletableFuture<Result> completableFuture = performanceTool.run("http://www.jd.com", 100);
try {
Result result = completableFuture.get();
log.info("AVG : "+ result.getAvg());
log.info("RT_95% : " + result.getRt_95Percentage());
} catch (InterruptedException e) {
log.error("InterruptedException has error !", e);
} catch (ExecutionException e) {
log.error("ExecutionException has error !", e);
}
}
}
class PerformanceThreadFactory implements ThreadFactory {
private ThreadGroup group;
private final String namePrefix;
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final AtomicInteger threadNumber = new AtomicInteger(1);
public PerformanceThreadFactory() {
SecurityManager securityManager = new SecurityManager();
this.group = securityManager.getThreadGroup();
StringBuilder sb = new StringBuilder();
sb.append("Performance-pool-").append(poolNumber.getAndIncrement())
.append("-thread-");
this.namePrefix = sb.toString();
}
* Constructs a new {@code Thread}. Implementations may also initialize
* priority, name, daemon status, {@code ThreadGroup}, etc.
*
* @param r a runnable to be executed by new thread instance
* @return constructed thread, or {@code null} if the request to
* create a thread is rejected
*/
@Override
public Thread newThread(Runnable r) {
return new Thread(this.group, r,
this.namePrefix + this.threadNumber.getAndIncrement(), 0L);
}
}
class Result {
private List<Integer> responseTimeList;
private Double avg;
private Integer rt_95Percentage;
public Result(List<Integer> responseTimeList) {
this.responseTimeList = responseTimeList;
cal();
}
private void cal(){
if(CollectionUtils.isNotEmpty(responseTimeList)) {
int sum = responseTimeList.stream()
.mapToInt(Integer::shortValue)
.sum();
this.avg = sum * 1d / responseTimeList.size();
Collections.sort(responseTimeList);
rt_95Percentage = responseTimeList.get((int) (responseTimeList.size() * 0.95)-1);
}
}
public List<Integer> getResponseTimeList() {
return (List<Integer>) Collections.unmodifiableCollection(responseTimeList);
}
public void setResponseTimeList(List<Integer> responseTimeList) {
this.responseTimeList = responseTimeList;
}
public Double getAvg() {
return avg;
}
public void setAvg(Double avg) {
this.avg = avg;
}
public Integer getRt_95Percentage() {
return rt_95Percentage;
}
public void setRt_95Percentage(Integer rt_95Percentage) {
this.rt_95Percentage = rt_95Percentage;
}
}
评论