这篇
,有详细整理过如何暴露监控端点。
其实 ThreadPool 本身已经提供了不少 api 可以获取线程状态:
很多方法看名字就知道其含义,只需要将这些信息暴露到 SpringBoot 的监控端点中,我们就可以在可视化页面查看当前的线程池状态了。
甚至我们可以继承线程池扩展其中的几个函数来自定义监控逻辑:
看这些名称和定义都知道,这是让子类来实现的。
可以在线程执行前、后、终止状态执行自定义逻辑。
Hystrix
已经帮我们实现了。
Hystrix 是一款开源的容错插件,具有依赖隔离、系统容错降级等功能。
下面来看看
Hystrix
简单的应用:
首先需要定义两个线程池,分别用于执行订单、处理用户。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
public class CommandOrder extends HystrixCommand<String> {
private final static Logger LOGGER = LoggerFactory.getLogger(CommandOrder.class);
private String orderName;
public CommandOrder(String orderName) {
super(Setter.withGroupKey( HystrixCommandGroupKey.Factory.asKey("OrderGroup")) .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("OrderPool"))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter() .withCoreSize(10) .withKeepAliveTimeMinutes(5) .withMaxQueueSize(10) .withQueueSizeRejectionThreshold(10000))
.andCommandPropertiesDefaults( HystrixCommandProperties.Setter() .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)) ) ; this.orderName = orderName; }
@Override public String run() throws Exception {
LOGGER.info("orderName=[{}]", orderName);
TimeUnit.MILLISECONDS.sleep(100); return "OrderName=" + orderName; }
}
public class CommandUser extends HystrixCommand<String> {
private final static Logger LOGGER = LoggerFactory.getLogger(CommandUser.class);
private String userName;
public CommandUser(String userName) {
super(Setter.withGroupKey( HystrixCommandGroupKey.Factory.asKey("UserGroup")) .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("UserPool"))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter() .withCoreSize(10) .withKeepAliveTimeMinutes(5) .withMaxQueueSize(10) .withQueueSizeRejectionThreshold(10000))
.andCommandPropertiesDefaults( HystrixCommandProperties.Setter() .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)) ) ; this.userName = userName; }
@Override public String run() throws Exception {
LOGGER.info("userName=[{}]", userName);
TimeUnit.MILLISECONDS.sleep(100); return "userName=" + userName; }
}
|
api
特别简洁易懂,具体详情请查看官方文档。
然后模拟运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
public static void main(String[] args) throws Exception { CommandOrder commandPhone = new CommandOrder("手机"); CommandOrder command = new CommandOrder("电视");
String execute = commandPhone.execute(); LOGGER.info("execute=[{}]", execute);
Future<String> queue = command.queue(); String value = queue.get(200, TimeUnit.MILLISECONDS); LOGGER.info("value=[{}]", value);
CommandUser commandUser = new CommandUser("张三"); String name = commandUser.execute(); LOGGER.info("name=[{}]", name); }
|
运行结果:
可以看到两个任务分成了两个线程池运行,他们之间互不干扰。
获取任务任务结果支持同步阻塞和异步非阻塞方式,可自行选择。
它的实现原理其实容易猜到:
利用一个 Map 来存放不同业务对应的线程池。
通过刚才的构造函数也能证明:
还要注意的一点是:
自定义的 Command 并不是一个单例,每次执行需要 new 一个实例,不然会报
This instance can only be executed once. Please instantiate a new instance.
异常。
https://github.com/crossoverJie/Java-Interview/tree/master/src/main/java/com/crossoverjie/hystrix
最后插播个小广告:
Java-Interview
截止目前将近 8K star。
这次定个小目标:争取冲击
1W star
。
感谢各位老铁的支持与点赞。
欢迎关注公众号一起交流: