如何正确设置Java线程池参数?「建议收藏」

如何正确设置Java线程池参数?「建议收藏」如何正确设置Java线程池参数?前言:在上篇文章我已经给读者介绍了Java线程池的基本使用,以及参数的定义。你真的了解Java线程池参数的含义吗本文我们更进一步,来聊聊在实际的工作中如何设置Java线程池参数的。当我们自定义线程池的时候corePoolSize、maximum…

大家好,又见面了,我是你们的朋友全栈君。

                                      如何正确设置Java线程池参数?

 

     前言:在上篇文章我已经给读者介绍了Java线程池的基本使用,以及参数的定义。你真的了解Java线程池参数的含义吗

    本文我们更进一步,来聊聊在实际的工作中如何设置Java线程池参数的。

 

  当我们自定义线程池的时候 corePoolSize、maximumPoolSize、workQueue(队列长度)该如何设置?

  你以为我要给你讲分 IO 密集型任务或者分 CPU 密集型任务?

  当然这个教科书式的流程我们决不能少!

  1:IO密集型任务时:

《Java并发编程实战》一书中给出的计算方式是这样的:

如何正确设置Java线程池参数?「建议收藏」

 

2:CPU密集型任务:

可以把核心线程数设置为核心数+1。

为什么要加一呢?

《Java并发编程实战》一书中给出的原因是:即使当计算(CPU)密集型的线程偶尔由于页缺失故障或者其他原因而暂停时,这个“额外”的线程也能确保 CPU 的时钟周期不会被浪费。

看不懂是不是?没关系我也看不懂。反正把它理解为一个备份的线程就行了。

 

教科书的痛点:

 

我之前有个系统就是按照这个公式算出来的参数去配置的。

结果效果并不好,甚至让下游系统直呼受不了。

这个东西怎么说呢,还是得记住,面试的时候有用。真实场景中只能得到一个参考值,基于这个参考值,再去进行调整。

我们再看一下美团的那篇文章调研的现有解决方案列表:

如何正确设置Java线程池参数?「建议收藏」

第一个就是我们上面说的,和实际业务场景有所偏离。

第二个设置为 2*CPU 核心数,有点像是把任务都当做 IO 密集型去处理了。而且一个项目里面一般来说不止一个自定义线程池吧?比如有专门处理数据上送的线程池,有专门处理查询请求的线程池,这样去做一个简单的线程隔离。但是如果都用这样的参数配置的话,显然是不合理的。

第三个不说了,理想状态。流量是不可能这么均衡的,就拿美团来说,下午3,4点的流量,能和 12 点左右午饭时的流量比吗?

基于上面的这些解决方案的痛点,美团给出了动态化配置的解决方案。

 

动态更新的工作原理是什么?

如何正确设置Java线程池参数?「建议收藏」

 

在运行期线程池使用方调用此方法设置corePoolSize之后,线程池会直接覆盖原来的corePoolSize值,并且基于当前值和原始值的比较结果采取不同的处理策略。

对于当前值小于当前工作线程数的情况,说明有多余的worker线程,此时会向当前idle的worker线程发起中断请求以实现回收,多余的worker在下次idel的时候也会被回收;

对于当前值大于原始值且当前队列中有待执行任务,则线程池会创建新的worker线程来执行队列任务,setCorePoolSize具体流程

 

因此动态更新线程参数的核心在于:

setCorePoolSize   setMaxNumPoolSize  以及重新设置队列长度三个方法。

由于美团的文章发表只是理论上的概念并未发布源码。

 

因此参考美团文章给出的思路我来尝试实现微服务的动态更新线程池参数的Stater.

1:新建一个动态调整线程池参数的Stater,命名为 iread-threadfactory

如何正确设置Java线程池参数?「建议收藏」

2: 由于需要调整最大线程数、核心线程数、队列长度三个参数,因此将三个参数做成可配置的,又因为需要辨别每个线程,因此还需要设置线程池的名字。因此建立如下配置类:

WoreadThreadFactoryProperties

package com.cn.woread.configuration;

import java.util.ArrayList;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@ConfigurationProperties(prefix = "woread.thread")
public class WoreadThreadFactoryProperties {
	
	
	
	
	List<Properties>list=new ArrayList<Properties>();

	public List<Properties> getList() {
		return list;
	}

	public void setList(List<Properties> list) {
		this.list = list;
	}


	
	

	
	
	
	
	
	
	
	

}

Properties

package com.cn.woread.configuration;

public class Properties {
	
	
	private String threadFactoryName;
	
	//最大线程数
	private int maximumPoolSize;
	
	//核心线程数
	private int corePoolSize;
	
	//队列大小
	private int capacity;
	
	
	

	public String getThreadFactoryName() {
		return threadFactoryName;
	}

	public void setThreadFactoryName(String threadFactoryName) {
		this.threadFactoryName = threadFactoryName;
	}

	public int getMaximumPoolSize() {
		return maximumPoolSize;
	}

	public void setMaximumPoolSize(int maximumPoolSize) {
		this.maximumPoolSize = maximumPoolSize;
	}

	public int getCorePoolSize() {
		return corePoolSize;
	}

	public void setCorePoolSize(int corePoolSize) {
		this.corePoolSize = corePoolSize;
	}

	public int getCapacity() {
		return capacity;
	}

	public void setCapacity(int capacity) {
		this.capacity = capacity;
	}

}

 

3:创建线程池创建处理类:WoreadThreadPoolExecture

package com.cn.woread.configuration;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;

public class WoreadThreadPoolExecture {

	
	private WoreadThreadFactoryProperties properties;
	
	private static Map<String,ThreadPoolExecutor> threadFactorys=new HashMap<String,ThreadPoolExecutor>();
	
	
	public WoreadThreadPoolExecture(WoreadThreadFactoryProperties properties) {
		this.properties=properties;
	}


	public ThreadPoolExecutor reBulidThreadFactory(String name) {
		List<Properties >list=properties.getList();
		ThreadPoolExecutor threadFactory=null;
		if(list!=null&&list.size()!=0) {
			Optional<Properties> mapOpt=list.stream().filter(l->name.equals(l.getThreadFactoryName())).findFirst();
			int maximumPoolSize=Runtime.getRuntime().availableProcessors() +1;
			int corePoolSize=maximumPoolSize;
			int capacity=1000;
			
			if(mapOpt.isPresent()) {
				Properties map=mapOpt.get();
				//最大线程数 
				 maximumPoolSize=map.getMaximumPoolSize();
				//核心线程数
				 corePoolSize=map.getCorePoolSize();
				//队列大小
				 capacity=map.getCapacity();
			}
			if(threadFactorys.containsKey(name)) {
				threadFactory=threadFactorys.get(name);
				threadFactory.setCorePoolSize(corePoolSize);
				threadFactory.setMaximumPoolSize(maximumPoolSize);
				WoreadLinkedBlockingQueue queue=(WoreadLinkedBlockingQueue)threadFactory.getQueue();
				queue.setCapacity(capacity);
				threadFactory.prestartAllCoreThreads();
			}else {
				threadFactory=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 60, TimeUnit.SECONDS, new WoreadLinkedBlockingQueue<Runnable>(capacity));
				threadFactorys.put(name, threadFactory);
			}
			
		}
		return threadFactory;
	}
	
	
	

}

该类只有一个方法:ThreadPoolExecutor reBulidThreadFactory(String name)

根据线程池名字创建相应参数的线程池(如果从未创建)

根据线程池名字创建相应参数的线程池(如果已经创建—实现动态调整参数的需求)

    private static Map<String,ThreadPoolExecutor> threadFactorys=new HashMap<String,ThreadPoolExecutor>();
 

   利用一个静态的map存储所有创建的线程池对象
      1          threadFactory.setCorePoolSize(corePoolSize);
      2          threadFactory.setMaximumPoolSize(maximumPoolSize);
      3          WoreadLinkedBlockingQueue queue=(WoreadLinkedBlockingQueue)threadFactory.getQueue();
      4         queue.setCapacity(capacity);
      5         threadFactory.prestartAllCoreThreads();

  1-2行代码利用配置文件配置的线程数量来重新设置线程参数,可是却未找到重新设置队列长度的方法,通过翻看源码发现,

 队列长度capacity被设置成了final对象,不可更改,因此我的做法是重写队列,将大小设置为可改变的,提供改变方法

 创建 线程队列类:WoreadLinkedBlockingQueue

  如何正确设置Java线程池参数?「建议收藏」

4:创建staer类WoreadThreadFactoryConfiguration

package com.cn.woread.stater;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.cn.woread.configuration.WoreadThreadFactoryProperties;
import com.cn.woread.configuration.WoreadThreadPoolExecture;

@Configuration
@EnableConfigurationProperties(WoreadThreadFactoryProperties.class)
public class WoreadThreadFactoryConfiguration {
	
	@Autowired
	private WoreadThreadFactoryProperties properties;
	
	@Bean
	@ConditionalOnMissingBean(WoreadThreadPoolExecture.class)
	public WoreadThreadPoolExecture woreadThreadPoolExecture() {
		return new WoreadThreadPoolExecture(properties);
	}
	

}

至此动态调整参数的线程池stater构建完毕。

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/139634.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • leetcode-138. 复制带随机指针的链表(链表)

    leetcode-138. 复制带随机指针的链表(链表)给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。例如,如果原链表中有 X 和 Y 两个节点,其中 X.random –> Y 。那么在复制链

    2022年8月9日
    6
  • 商汤组了「最强大脑」局,正儿八经解释为啥搞起电竞AI「建议收藏」

    商汤组了「最强大脑」局,正儿八经解释为啥搞起电竞AI「建议收藏」金磊发自凹非寺量子位报道|公众号QbitAI前不久,《星际争霸2》虫王iA周航加入商汤科技,担任AI研究员。堪称电竞职业玩家「转型最成功」的案例之一。而商汤作为一家以计算机视…

    2022年5月16日
    42
  • msfconsole是什么意思_msfconsole渗透手机

    msfconsole是什么意思_msfconsole渗透手机先模拟多层内网,摸清后渗透的使用,再从学校入手。内网渗透test网络拓扑以kali为攻击机,xp作为跳板主机,win7是内网主机xp主机是提供web,FTP等服务,已被kali机获取shellwin7正常不与外网访问,和DMZ区域处于同一网段环境搭建使用VMware的主机模式,构建虚拟局域网。查看Host-only模式详解虚拟网络编译器中添加两块网卡vm1,vm2。类型:主…

    2022年9月7日
    1
  • MySQL数据类型选择「建议收藏」

    MySQL数据类型选择「建议收藏」前言在MySQL中,选择正确的数据类型,对于性能至关重要。一般应从以下两个方面考量:确定合适的大类型:数值、字符串、时间、二进制;确定具体的类型:有无符号、取值范围、变长定长等。在MySQL数据类型设置方面,尽量采用更小的数据类型,因为它们占用的存储空间更小,通常有更好的性能,花费更少的硬件资源。并且,尽量把字段定义为NOTNULL,避免使用NULL。1.字符串类型类型大小用途CHAR0-255字节定长字符串,char(n)当插入的字符串实际长度不足n时,插

    2022年9月20日
    0
  • python转置矩阵代码_python 矩阵转置[通俗易懂]

    python转置矩阵代码_python 矩阵转置[通俗易懂]用python怎么实现矩阵的转置只能用循环自己写算法吗自带函数有可以算的吗或者网上的算法可以用的python矩阵转置怎么做?5.矩阵转置给定:L=[[1,2,3],[4,5,6]]用zip函数和列表推导式实现行列转deftranspose(L):T=[list(tpl)fortplinzip(*L)]returnTpython字符串如何变成矩阵进行矩阵转置如输入一串“…

    2022年5月5日
    58
  • 什么是ADO.NET

    什么是ADO.NET

    2021年7月31日
    54

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号