【SpringCloud】HystrixCommand的threadPoolKey默認值及線程池初始化

關于threadPoolKey默認值的疑問

使用SpingCloud必然會用到Hystrix做熔斷降級,也必然會用到@HystrixCommand注解,@HystrixCommand注解可以配置的除了常用的groupKey、commandKey、fallbackMethod等,還有一個很關鍵的就是threadPoolKey,就是使用Hystrix線程隔離策略時的線程池Key

/**
 * This annotation used to specify some methods which should be processes as hystrix commands.
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HystrixCommand {

    /**
     * The command group key is used for grouping together commands such as for reporting,
     * alerting, dashboards or team/library ownership.
     * <p/>
     * default => the runtime class name of annotated method
     *
     * @return group key
     */
    String groupKey() default "";

    /**
     * Hystrix command key.
     * <p/>
     * default => the name of annotated method. for example:
     * <code>
     *     ...
     *     @HystrixCommand
     *     public User getUserById(...)
     *     ...
     *     the command name will be: 'getUserById'
     * </code>
     *
     * @return command key
     */
    String commandKey() default "";

    /**
     * The thread-pool key is used to represent a
     * HystrixThreadPool for monitoring, metrics publishing, caching and other such uses.
     *
     * @return thread pool key
     */
    String threadPoolKey() default "";
    
    ......省略
}

而使用中我們常常只指定fallbackMethod回退方法,而不會指定所有屬性,從@HystrixCommand的源碼注釋來看

  • groupKey的默認值是使用@HystrixCommand標注的方法所在的類名
  • commandKey的默認值是@HystrixCommand標注的方法名,即每個方法會被當做一個HystrixCommand
  • threadPoolKey沒有默認值

但threadPoolKey卻沒有說明默認值,而threadPoolKey是和執行HystrixCommand的線程池直接相關的

所以我的疑問就是,threadPoolKey有默認值嗎? 默認值是什么? 執行HystrixCommand的線程池又是怎么初始化的? 可以動態調整嗎?

測試論證

測試代碼

spring-cloud-example-consumer-ribbon-hystrix-threadpool

測試端點及方式

首先需要啟動 spring-cloud-example-eureka-server-standalone注冊中心spring-cloud-example-simple-provider服務提供者

再啟動 spring-cloud-example-consumer-ribbon-hystrix-threadpool

測試端點

http://127.0.0.1:20006/testDefaultThreadPoolKey

http://127.0.0.1:20006/testDefaultThreadPoolKey2

testDefaultThreadPoolKey 和 testDefaultThreadPoolKey2 是同一個service的兩個方法,分別使用@HystrixCommand指定fallback方法

線程池大小設置為2,且不使用隊列暫存,服務提供方sleep 30秒,通過chrome多窗口調用 /testDefaultThreadPoolKey 端點

或同時調用 /testDefaultThreadPoolKey/testDefaultThreadPoolKey2 端點
通過大于線程池最大值的請求被線程池拒絕進入fallback,判斷線程池是方法級,還是類級的,以及threadPoolKey默認值

注意:

使用firefox瀏覽器測試有問題,多標簽頁必須等待一個GET請求完成,才能繼續下一個,測不出并發的效果。

一開始以為是程序上的限制,后來才發現是瀏覽器,使用chrome問題解決

線程池配置

hystrix.threadpool.default.coreSize = 2
hystrix.threadpool.default.maximumSize = 2
hystrix.threadpool.default.maxQueueSize = -1

線程池的coreSizemaximumSize都設置為2(1.5.9版本后才添加maximumSize),且線程池隊列大小為-1,即使用SynchronousQueue

Hystrix線程池的其它屬性: Hystrix Thread Pool Properties

測試結果

1542010160835.png

chrome瀏覽器連續GET請求調用6次,分別調用3次 /testDefaultThreadPoolKey,3次 /testDefaultThreadPoolKey2,以綠色線問分隔,可見前兩次調用成功,后4次均直接拒絕,進入fallback

具體異常信息為:

java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@6d72dcf rejected from java.util.concurrent.ThreadPoolExecutor@431bfebc[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 1]

線程池大小為2起到了作用,將大于并發數的請求拒絕了,并且無論是只調用 /testDefaultThreadPoolKey,還是輪詢調用 /testDefaultThreadPoolKey/testDefaultThreadPoolKey2 ,測試結果都是這樣。再根據hystrix線程的名字 hystrix-ConsumerRibbonHystrixThreadPoolService-n,可以猜想:Hystrix的 threadPoolKey是和hystrixCommand執行的類相關的,可能一個類使用一個線程池,所以兩個service方法才會共用線程池

原理分析

HystrixCommandAspect

首先,被@HystrixCommand注解標注的方法會被AOP攔截,具體邏輯在 HystrixCommandAspect

private static final Map<HystrixPointcutType, MetaHolderFactory> META_HOLDER_FACTORY_MAP;

// 初始化用于處理 HystrixCommand 和 HystrixCollapser 的 MetaHolderFactory
// HystrixCommand -- CommandMetaHolderFactory
// HystrixCollapser -- CollapserMetaHolderFactory
static {
    META_HOLDER_FACTORY_MAP = ImmutableMap.<HystrixPointcutType, MetaHolderFactory>builder()
            .put(HystrixPointcutType.COMMAND, new CommandMetaHolderFactory())
            .put(HystrixPointcutType.COLLAPSER, new CollapserMetaHolderFactory())
            .build();
}


// HystrixCommand Pointcut切入點
@Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")
public void hystrixCommandAnnotationPointcut() {
}

// HystrixCollapser Pointcut切入點
@Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
public void hystrixCollapserAnnotationPointcut() {
}

// HystrixCommand 和 HystrixCollapser 的環繞通知
@Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
    Method method = getMethodFromTarget(joinPoint);
    Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
    if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
        throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
                "annotations at the same time");
    }
    
    // 創建metaHolder,用于保存元數據
    MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
    MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
    
    // 創建HystrixCommand,HystrixInvokable是父接口
    HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
    ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
            metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();

    // 執行HystrixCommand
    Object result;
    try {
        if (!metaHolder.isObservable()) {
            result = CommandExecutor.execute(invokable, executionType, metaHolder);
        } else {
            result = executeObservable(invokable, executionType, metaHolder);
        }
    } catch (HystrixBadRequestException e) {
        throw e.getCause() != null ? e.getCause() : e;
    } catch (HystrixRuntimeException e) {
        throw hystrixRuntimeExceptionToThrowable(metaHolder, e);
    }
    return result;
}

重點是methodsAnnotatedWithHystrixCommand()環繞通知的實現方法

其中MetaHolder metaHolder = metaHolderFactory.create(joinPoint)根據joinPoint的信息創建元數據時肯定會有初始化默認groupKey、默認commandKey以及默認threadPoolKey的邏輯

創建MetaHolder元數據

private static class CommandMetaHolderFactory extends MetaHolderFactory {
    @Override
    public MetaHolder create(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {
        HystrixCommand hystrixCommand = method.getAnnotation(HystrixCommand.class);
        ExecutionType executionType = ExecutionType.getExecutionType(method.getReturnType());
        
        // 創建MetaHolderBuilder
        MetaHolder.Builder builder = metaHolderBuilder(proxy, method, obj, args, joinPoint);
        if (isCompileWeaving()) {
            builder.ajcMethod(getAjcMethodFromTarget(joinPoint));
        }
        
        return builder.defaultCommandKey(method.getName())  //默認commandKey是方法名
                        .hystrixCommand(hystrixCommand)
                        .observableExecutionMode(hystrixCommand.observableExecutionMode())
                        .executionType(executionType)
                        .observable(ExecutionType.OBSERVABLE == executionType)
                        .build();
    }
}


//----------再來看看創建MetaHolderBuilder - metaHolderBuilder()
//== MetaHolderFactory#metaHolderBuilder()
MetaHolder.Builder metaHolderBuilder(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {
    MetaHolder.Builder builder = MetaHolder.builder()
            .args(args).method(method).obj(obj).proxyObj(proxy)
            .joinPoint(joinPoint);

    // 設置fallback方法
    setFallbackMethod(builder, obj.getClass(), method);
    // 設置默認配置
    builder = setDefaultProperties(builder, obj.getClass(), joinPoint);
    
    return builder;
}

//== 設置默認配置 setDefaultProperties()
private static MetaHolder.Builder setDefaultProperties(MetaHolder.Builder builder, Class<?> declaringClass, final ProceedingJoinPoint joinPoint) {
    //根據@DefaultProperties注解獲取配置
    Optional<DefaultProperties> defaultPropertiesOpt = AopUtils.getAnnotation(joinPoint, DefaultProperties.class);
    //設置 默認groupKey為類名simpleName
    builder.defaultGroupKey(declaringClass.getSimpleName());
    
    //如果存在@DefaultProperties,使用其指定的groupKey、threadPoolKey
    if (defaultPropertiesOpt.isPresent()) {
        DefaultProperties defaultProperties = defaultPropertiesOpt.get();
        builder.defaultProperties(defaultProperties);
        if (StringUtils.isNotBlank(defaultProperties.groupKey())) {
            builder.defaultGroupKey(defaultProperties.groupKey());
        }
        if (StringUtils.isNotBlank(defaultProperties.threadPoolKey())) {
            builder.defaultThreadPoolKey(defaultProperties.threadPoolKey());
        }
    }
    return builder;
}

由此可見,在構造metaHolder元數據時,通過@HystrixCommand標準方法所在的類名作為goutpKey,通過方法名作為commandKey,但沒有指定threadPoolKey

但執行HystrixCommand時是有默認threadPoolKey的,那么這個默認值從何而來,command又是怎么初始化線程池的呢??

通過metaHolder構造HystrixCommandBuilder

//----------HystrixCommandFactory#create()
public HystrixInvokable create(MetaHolder metaHolder) {
    HystrixInvokable executable;
    if (metaHolder.isCollapserAnnotationPresent()) {
        executable = new CommandCollapser(metaHolder);
    } 
    else if (metaHolder.isObservable()) {
        executable = new GenericObservableCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));
    } 
    else {
        //通過metaHolder構造HystrixCommandBuilder,再創建GenericCommand
        executable = new GenericCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));
    }
    return executable;
}


//----------HystrixCommandBuilderFactory#create()  創建HystrixCommandBuilder
//在創建HystrixCommandBuilder時,createGenericSetterBuilder(metaHolder)構造了Setter,是用于設置groupKey、commandKey、threadPoolKey的
public <ResponseType> HystrixCommandBuilder create(MetaHolder metaHolder, Collection<HystrixCollapser.CollapsedRequest<ResponseType, Object>> collapsedRequests) {
    validateMetaHolder(metaHolder);

    return HystrixCommandBuilder.builder()
            .setterBuilder(createGenericSetterBuilder(metaHolder)) //重點:設置setterBuilder
            .commandActions(createCommandActions(metaHolder))
            .collapsedRequests(collapsedRequests)
            .cacheResultInvocationContext(createCacheResultInvocationContext(metaHolder))
            .cacheRemoveInvocationContext(createCacheRemoveInvocationContext(metaHolder))
            .ignoreExceptions(metaHolder.getCommandIgnoreExceptions())
            .executionType(metaHolder.getExecutionType())
            .build();
}

//----------createGenericSetterBuilder()  創建SetterBuilder
private GenericSetterBuilder createGenericSetterBuilder(MetaHolder metaHolder) {
    GenericSetterBuilder.Builder setterBuilder = GenericSetterBuilder.builder()
            .groupKey(metaHolder.getCommandGroupKey())
            .threadPoolKey(metaHolder.getThreadPoolKey()) //查看從metaHolder如何獲取threadPoolKey
            .commandKey(metaHolder.getCommandKey())
            .collapserKey(metaHolder.getCollapserKey())
            .commandProperties(metaHolder.getCommandProperties())
            .threadPoolProperties(metaHolder.getThreadPoolProperties())
            .collapserProperties(metaHolder.getCollapserProperties());
    if (metaHolder.isCollapserAnnotationPresent()) {
        setterBuilder.scope(metaHolder.getHystrixCollapser().scope());
    }
    return setterBuilder.build();
}

//如果使用了Command注解,從注解指定的threadPoolKey 和 defaultThreadPoolKey二選一,以前者為主
//本例中,既沒有通過注解指定threadPoolKey,也沒有defaultThreadPoolKey
public String getThreadPoolKey() {
    return isCommandAnnotationPresent() ? get(hystrixCommand.threadPoolKey(), defaultThreadPoolKey) : "";
}

從上面看,HystrixCommandBuilder都構造完成了,還沒有設置threadPoolKey

通過HystrixCommandBuilder創建HystrixCommand

下面是通過HystrixCommandBuilder作為參數創建GenericCommand(),即通過HystrixCommandBuilder創建HystrixCommand

GenericCommand的類圖為:

1542074599975.png

可見GenericCommand集成關系,從AbstractHystrixCommand --> HystrixCommand --> AbstractCommand,最終他們都是HystrixInvokeable接口的實現了,即可被Hystrix調用的

向上進入父類構造,HystrixCommand(Setter setter)

protected HystrixCommand(Setter setter) {
    // use 'null' to specify use the default
    this(setter.groupKey, setter.commandKey, setter.threadPoolKey, null, null, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, null, null, null, null, null);
}

從setter中獲取了groupKey、commandKey、threadPoolKey、commandPropertiesDefaults、threadPoolPropertiesDefaults,其它參數為null

AbstractCommand構造

進入到 AbstractCommand構造方法,封裝了構造一個HystrixCommand的基本上所有元素的邏輯

protected AbstractCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool,
        HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults,
        HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore,
        HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) {

    this.commandGroup = initGroupKey(group); //初始化commandGroupKey
    this.commandKey = initCommandKey(key, getClass()); //初始化commandKey
    this.properties = initCommandProperties(this.commandKey, propertiesStrategy, commandPropertiesDefaults); //初始化commandProperties
    this.threadPoolKey = initThreadPoolKey(threadPoolKey, this.commandGroup, this.properties.executionIsolationThreadPoolKeyOverride().get()); //初始化threadPoolKey
    this.metrics = initMetrics(metrics, this.commandGroup, this.threadPoolKey, this.commandKey, this.properties); //初始化metrics
    this.circuitBreaker = initCircuitBreaker(this.properties.circuitBreakerEnabled().get(), circuitBreaker, this.commandGroup, this.commandKey, this.properties, this.metrics); //初始化斷路器
    this.threadPool = initThreadPool(threadPool, this.threadPoolKey, threadPoolPropertiesDefaults); //初始化線程池

    //Strategies from plugins
    this.eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
    this.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
    HystrixMetricsPublisherFactory.createOrRetrievePublisherForCommand(this.commandKey, this.commandGroup, this.metrics, this.circuitBreaker, this.properties);
    this.executionHook = initExecutionHook(executionHook);

    this.requestCache = HystrixRequestCache.getInstance(this.commandKey, this.concurrencyStrategy);
    this.currentRequestLog = initRequestLog(this.properties.requestLogEnabled().get(), this.concurrencyStrategy);

    /* fallback semaphore override if applicable */
    this.fallbackSemaphoreOverride = fallbackSemaphore;

    /* execution semaphore override if applicable */
    this.executionSemaphoreOverride = executionSemaphore;
}

接下來主要看是如何初始化threadPoolKey,以及threadPool的

initThreadPoolKey()

initThreadPoolKey(threadPoolKey, this.commandGroup, this.properties.executionIsolationThreadPoolKeyOverride().get())

參數:

  • threadPoolKey -- 指定的 或 默認的threadPoolKey

  • this.commandGroup -- 當前的groupKey

  • this.properties.executionIsolationThreadPoolKeyOverride().get()) -- 字符串類型,允許動態覆蓋修改HystrixThreadPoolKey的值,并將動態更新HystrixCommand執行的HystrixThreadPool,這個override值的典型值是null,并且在構造HystrixCommandProperties時override全局的配置為null

    // threadpool doesn't have a global override, only instance level makes sense
    this.executionIsolationThreadPoolKeyOverride = forString().add(propertyPrefix + ".command." + key.name() + ".threadPoolKeyOverride", null).build();
    

接著看 initThreadPoolKey() 方法內部

/*
 * ThreadPoolKey
 *
 * This defines which thread-pool this command should run on.
 *
 * It uses the HystrixThreadPoolKey if provided, then defaults to use HystrixCommandGroup.
 * 如果提供了threadPoolKey,就使用,否則默認使用groupKey
 *
 * It can then be overridden by a property if defined so it can be changed at runtime.
 * 可以被threadPoolKeyOverride在運行時動態覆蓋
 */
private static HystrixThreadPoolKey initThreadPoolKey(HystrixThreadPoolKey threadPoolKey, HystrixCommandGroupKey groupKey, String threadPoolKeyOverride) {
    if (threadPoolKeyOverride == null) {
        // we don't have a property overriding the value so use either HystrixThreadPoolKey or HystrixCommandGroup
        if (threadPoolKey == null) {
            /* 
             * use HystrixCommandGroup if HystrixThreadPoolKey is null 
             * 如果HystrixThreadPoolKey為空,使用groupKey作為threadPoolKey
             */
            return HystrixThreadPoolKey.Factory.asKey(groupKey.name());
        } else {
            return threadPoolKey;
        }
    } else {
        // we have a property defining the thread-pool so use it instead
        return HystrixThreadPoolKey.Factory.asKey(threadPoolKeyOverride);
    }
}

可見,在最開始構造HystrixCommand時,threadPoolKeyOverride為null,且沒有自己指定的threadPoolKey,也沒有默認的threadPoolKey,那么將使用groupKey作為threadPoolKey

所以,默認使用groupKey作為threadPoolKey,而group默認值是標注了@HystrixCommand的類名

最后,看一下如何根據threadPoolKey,初始化threadPool

initThreadPool()

//----------AbstractCommand#initThreadPool()
private static HystrixThreadPool initThreadPool(HystrixThreadPool fromConstructor, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults) {
    // fromConstructor為null,使用HystrixThreadPool.Factory創建線程池
    if (fromConstructor == null) {
        // get the default implementation of HystrixThreadPool
        return HystrixThreadPool.Factory.getInstance(threadPoolKey, threadPoolPropertiesDefaults);
    } else {
        return fromConstructor;
    }
}


//----------HystrixThreadPool.Factory#getInstance()  獲取HystrixThreadPool實例
static HystrixThreadPool getInstance(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter propertiesBuilder) {
    // get the key to use instead of using the object itself so that if people forget to implement equals/hashcode things will still work
    String key = threadPoolKey.name();

    // this should find it for all but the first time
    // 從緩存threadPools中獲取HystrixThreadPool,有則直接返回
    HystrixThreadPool previouslyCached = threadPools.get(key);
    if (previouslyCached != null) {
        return previouslyCached;
    }

    // if we get here this is the first time so we need to initialize
    // 第一次初始化HystrixThreadPool
    synchronized (HystrixThreadPool.class) {
        if (!threadPools.containsKey(key)) {
            threadPools.put(key, new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder));
        }
    }
    return threadPools.get(key);
}

先根據threadPoolKey嘗試從threadPools這個ConcurrentHashMap<String, HystrixThreadPool>中獲取,即從線程池緩存中獲取,有就直接返回previouslyCached之前的緩存,如果沒有,synchromized對HystrixThreadPool類上鎖后,再次判斷還是沒有threadPoolKey的緩存,就 new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder)

//----------new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder)
public HystrixThreadPoolDefault(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter propertiesDefaults) {
    this.properties = HystrixPropertiesFactory.getThreadPoolProperties(threadPoolKey, propertiesDefaults); //threadPoolProperties
    HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy(); //并發策略
    this.queueSize = properties.maxQueueSize().get(); //線程池隊列大小

    //創建HystrixThreadPoolMetrics,其中concurrencyStrategy.getThreadPool()會創建線程池
    this.metrics = HystrixThreadPoolMetrics.getInstance(threadPoolKey,
            concurrencyStrategy.getThreadPool(threadPoolKey, properties),
            properties);
    this.threadPool = this.metrics.getThreadPool();
    this.queue = this.threadPool.getQueue();

    /* strategy: HystrixMetricsPublisherThreadPool */
    HystrixMetricsPublisherFactory.createOrRetrievePublisherForThreadPool(threadPoolKey, this.metrics, this.properties);
}


//----------HystrixConcurrencyStrategy#getThreadPool(HystrixThreadPoolKey, HystrixThreadPoolProperties)
// concurrencyStrategy.getThreadPool()時會創建ThreadPoolExecutor
public ThreadPoolExecutor getThreadPool(final HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {
    final ThreadFactory threadFactory = getThreadFactory(threadPoolKey);

    final boolean allowMaximumSizeToDivergeFromCoreSize = threadPoolProperties.getAllowMaximumSizeToDivergeFromCoreSize().get(); //是否允許maximumSize生效
    final int dynamicCoreSize = threadPoolProperties.coreSize().get(); //動態coreSize
    final int keepAliveTime = threadPoolProperties.keepAliveTimeMinutes().get(); //大于coreSize的線程,未使用的?;顣r間
    final int maxQueueSize = threadPoolProperties.maxQueueSize().get(); //線程隊列最大值
    final BlockingQueue<Runnable> workQueue = getBlockingQueue(maxQueueSize);

    //允許使用maximumSize
    if (allowMaximumSizeToDivergeFromCoreSize) {
        final int dynamicMaximumSize = threadPoolProperties.maximumSize().get();
        
        //dynamicCoreSize > dynamicMaximumSize,打印error
        if (dynamicCoreSize > dynamicMaximumSize) {
            logger.error("Hystrix ThreadPool configuration at startup for : " + threadPoolKey.name() + " is trying to set coreSize = " +
                    dynamicCoreSize + " and maximumSize = " + dynamicMaximumSize + ".  Maximum size will be set to " +
                    dynamicCoreSize + ", the coreSize value, since it must be equal to or greater than the coreSize value");
            return new ThreadPoolExecutor(dynamicCoreSize, dynamicCoreSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);
        } 
        //dynamicCoreSize <= dynamicMaximumSize,正常
        else { 
            return new ThreadPoolExecutor(dynamicCoreSize, dynamicMaximumSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);
        }
    } 
    else { //不允許使用maximumSize
        return new ThreadPoolExecutor(dynamicCoreSize, dynamicCoreSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);
    }
}

至此,線程池創建完畢

結論

  • threadPoolKey的默認值是groupKey,而groupKey默認值是@HystrixCommand標注的方法所在類名

  • 可以通過在類上加@DefaultProperties( threadPoolKey="xxx" )設置默認的threadPoolKey

  • 可以通過@HystrixCommand( threadPoolKey="xxx" ) 指定當前HystrixCommand實例的threadPoolKey

  • threadPoolKey用于從線程池緩存中獲取線程池 和 初始化創建線程池,由于默認以groupKey即類名為threadPoolKey,那么默認所有在一個類中的HystrixCommand共用一個線程池

  • 動態配置線程池 -- 可以通過hystrix.command.HystrixCommandKey.threadPoolKeyOverride=線程池key動態設置threadPoolKey,對應的HystrixCommand所使用的線程池也會重新創建,還可以繼續通過hystrix.threadpool.HystrixThreadPoolKey.coreSize=nhystrix.threadpool.HystrixThreadPoolKey.maximumSize=n動態設置線程池大小

    注意: 通過threadPoolKeyOverride動態修改threadPoolKey之后,hystrixCommand會使用新的threadPool,但是老的線程池還會一直存在,并沒有觸發shutdown的機制

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容