java线程池最大线程数-java线程池执行完毕
文章目录
前言
线程池在 Java 服务中无处不在,但确切的线程数是合适的通常是一个意见问题。在这里,总结一下我看到的观点,并根据我的个人经验做一些总结。
一、经典方法
摘自 Java 并发编程的实际应用
二、要点分析 1.确定 CPU 的数量
int N_CPUS = Runtime.getRuntime().availiableProcessors();
此代码是 JDK 提供的解决方案。通常,它在物理机器上是准确的。但是,在云原生/虚拟化环境中,笔者遇到了获取结果数量多于实际数量的情况,导致线程过多。所以代码可以这样写,实际操作还是需要确认的。另外,所谓的可用处理器,其实都是可用的处理器内核,毕竟可能只有1个处理器,但有8个内核。
2. 确定任务类型
工程实践中的任务类型可能是I/O密集型的,可能是计算密集型的,也可能是两者的混合,即混合任务。虽然好的设计应该是将I / O过程和计算过程分开的设计,但也有一些遗留系统具有许多非常规逻辑,由于各种历史原因,将两者组合在一个线程中。因此java线程池最大线程数,根据经验确定的任务类型可能不准确。最终,通过等待/计算比率来衡量任务的类型更为合理。作为开发人员,我们仍然需要与数据对话。所以让这个逻辑连续运行几次,你可以看到区别。以下命令和结果是 CentOS。
查看线程状态
tpid 是线程 ID,这里以 grpc boss 事件循环线程为例
cat /proc/${tpid}/status
cat /proc/27792/status
Name: grpc-nio-boss-E
Umask: 0022
State: S (sleeping)
Tgid: 27738
Ngid: 0
Pid: 27792
PPid: 1
TracerPid: 0
Uid: 18930 18930 18930 18930
Gid: 1001 1001 1001 1001
FDSize: 256
Groups: 1001 3007 3030
VmPeak: 2958948 kB
VmSize: 2958944 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 550244 kB
VmRSS: 550244 kB
RssAnon: 536192 kB
RssFile: 14052 kB
RssShmem: 0 kB
VmData: 2795616 kB
VmStk: 132 kB
VmExe: 4 kB
VmLib: 19012 kB
VmPTE: 1460 kB
VmSwap: 0 kB
Threads: 53
SigQ: 0/14120
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000004
SigIgn: 0000000000000003
SigCgt: 2000000181005ccc
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000001fffffffff
CapAmb: 0000000000000000
Seccomp: 0
Speculation_Store_Bypass: vulnerable
Cpus_allowed: 3
Cpus_allowed_list: 0-1
Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list: 0
# 线程自愿上下文切换
voluntary_ctxt_switches: 12127
# 线程非自愿上下文切换
nonvoluntary_ctxt_switches: 4
非自愿上下文切换 /
资源上下文切换非常大 表示线程经常主动放弃 CPU 时间片,通常是在等待其他资源,如 I/O 完成、等待锁定等。此处的单位是时间,可以是定性的,但不提供确切的运行/等待比率。
查看线程调度状态
PID:进程 ID,TPID:线程 ID
cat /proc/${pid or tpid}/sched
cat /proc/27792/sched
grpc-nio-boss-E (27792, #threads: 53)
-------------------------------------------------------------------
se.exec_start : 10308747122.791804
// 虚拟运行总时间(等待时间+使用CPU时间)
se.vruntime : 52693327.134406
// 实际运行总时间(使用CPU时间)
se.sum_exec_runtime : 1285.444999
// 跨CPU核心切换次数
se.nr_migrations : 2446
// 上下文切换总次数
nr_switches : 12131
// 自愿切换次数
nr_voluntary_switches : 12127
// 非自愿切换次数
nr_involuntary_switches : 4
se.load.weight : 1024
policy : 0
// 线程优先级
prio : 120
clock-delta : 36
mm->numa_scan_seq : 0
numa_migrations, 0
numa_faults_memory, 0, 0, 1, 0, -1
numa_faults_memory, 1, 0, 0, 0, -1
使用 se.se.vruntime,se.sum_exec_runtime,我们可以得到一个相对合理的等待/计算比率。
严格来说,这个比例不是那么准确。因为,如果线程的任务有很多条件分支,导致任务不同,则比率将大幅波动并失去其参考意义。结果java线程池最大线程数,糟糕的设计带来了无数的不确定性,限制了经验和理论的作用。
此时,我们可以应用公式并愉快地确定线程数。但是,现实可能有点复杂,所以让我们谈谈这些限制。
3. 工程限制 垂直限制
线程池中的任务依赖于其他下游资源。例如,连接池中的连接。假设线程池设置为 30,而连接池最多只允许 20 个,则仍有 10 个线程在等待,因为它们无法获取链接。再比如通过网络进行大批量数据传输,内核TCP窗口太小或者对方接收太慢,导致Socket发送缓存总是被填满,发送线程只能等待。
横向限制
JVM一次性内存不足以支持更多的并发性;通常进程中有多个线程池,有多个类似任务的线程池,线程优先级设置会影响最终的W/C比率。
总结
以上就是我今天要讲的,本文对设置线程数的方法、元素和工程限制做了一些个人总结,希望对大家有所帮助。如果你有更好的方法,也欢迎你射砖,谢谢你的阅读。