All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sviolet.thistle.model.concurrent.LoadRunner Maven / Gradle / Ivy

/*
 * Copyright (C) 2015-2022 S.Violet
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Project GitHub: https://github.com/shepherdviolet/thistle
 * Email: [email protected]
 */

package sviolet.thistle.model.concurrent;

import sviolet.thistle.util.concurrent.ThreadPoolExecutorUtils;

import java.io.Closeable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 

负载执行器(用于压测)

*

多线程执行同一个任务, 可以实时调整并发数/时间间隔, 需要调用start方法启动, 调用close方法停止.

*

*

注意:

*

1.设置完毕后, 调用start方法启动.

*

2.记得调用close方法停止, 但执行线程不会立刻终止, 要等单个任务执行完毕才会停止.

*

3.配合Apollo之类的配置中心使用更佳, 执行参数可以实时调整(实时生效).

*

4.压测的时候, 关闭程序的日志输出能大大提高TPS, 可以只保留必要的日志写盘. 日志输出到磁盘性能影响巨大, 输出到Console性能影响较小.

* * @author shepherdviolet */ public class LoadRunner implements AutoCloseable, Closeable { private final Task task; private volatile boolean started = false; private volatile int maxThreadNum = 0; private volatile int intervalMillis = 0; private volatile long startupDelay = 0L; private volatile long createThreadDelay = 0L; private final AtomicInteger currentThreadNum = new AtomicInteger(0); private final ExecutorService dispatcherThreadPool = ThreadPoolExecutorUtils.createLazy(10, "LoadRunner-dispatcher"); private final ExecutorService workerThreadPool = ThreadPoolExecutorUtils.createCached(0, Integer.MAX_VALUE, 10, "LoadRunner-worker-%d"); /** * @param task 执行的任务 * @param maxThreadNum 最大线程数 * @param intervalMillis 单线程执行间隔 */ public LoadRunner(Task task, int maxThreadNum, int intervalMillis) { if (task == null) { throw new IllegalArgumentException("task is null"); } if (maxThreadNum < 0) { throw new IllegalArgumentException("maxThreadNum < 0"); } if (intervalMillis < 0) { throw new IllegalArgumentException("intervalMillis < 0"); } this.task = task; this.maxThreadNum = maxThreadNum; this.intervalMillis = intervalMillis; } /** * 设置最大执行线程数 * @param maxThreadNum 最大执行线程数 */ public LoadRunner setMaxThreadNum(int maxThreadNum) { this.maxThreadNum = maxThreadNum; if (started) { dispatcherThreadPool.execute(DISPATCH_TASK); } return this; } /** * 设置每个线程执行任务的间隔 * @param intervalMillis 每个线程执行任务的间隔, ms */ public LoadRunner setIntervalMillis(int intervalMillis) { this.intervalMillis = intervalMillis; return this; } /** * 设置启动延迟, 每次启动(start)或追加线程(setMaxThreadNum)前, 会延迟指定时间 * @param startupDelay 启动延迟, ms */ public LoadRunner setStartupDelay(long startupDelay){ this.startupDelay = startupDelay; return this; } /** * 设置线程创建延迟, 每创建一个新的执行线程前, 会延迟指定时间 * @param createThreadDelay 线程创建延迟, ms */ public LoadRunner setCreateThreadDelay(long createThreadDelay){ this.createThreadDelay = createThreadDelay; return this; } /** * 启动 */ public LoadRunner start() { started = true; dispatcherThreadPool.execute(DISPATCH_TASK); return this; } /** * 停止, 不会打断执行中的线程 */ @Override public void close() { started = false; } public int getMaxThreadNum() { return maxThreadNum; } public int getIntervalMillis() { return intervalMillis; } public int getCurrentThreadNum() { return currentThreadNum.get(); } private final Runnable DISPATCH_TASK = new Runnable() { @Override public void run() { if (startupDelay > 0L) { try { Thread.sleep(startupDelay); } catch (InterruptedException ignore) { } } for (int i = 0 ; i < maxThreadNum && started && currentThreadNum.get() < maxThreadNum ; i++) { if (createThreadDelay > 0L) { try { //noinspection BusyWait Thread.sleep(createThreadDelay); } catch (InterruptedException ignore) { } } workerThreadPool.execute(new Runnable() { @Override public void run() { int id = currentThreadNum.getAndIncrement(); while (started && id < maxThreadNum) { try { if (intervalMillis > 0L) { //noinspection BusyWait Thread.sleep(intervalMillis); } task.onExecute(id); } catch (InterruptedException ignore) { } catch (Throwable t) { try { task.onException(id, t); } catch (Throwable ignore) { } } } currentThreadNum.getAndDecrement(); } }); } } }; /** * 任务 */ public interface Task { /** * 任务执行代码 */ void onExecute(int id); /** * 异常处理 */ void onException(int id, Throwable t); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy