精华内容
下载资源
问答
  • java线程数的设置和cpu关系
    千次阅读
    2018-11-21 10:43:16

    cpu采用分片机制执行线程,给每个线程划分很小的时间颗粒去执行,但是真正的项目中,一个程序要做很多的操作,读写磁盘、数据逻辑处理,处于业务需求必要的休眠等等操作,当程序在进行I/O操作的时候,线程是阻塞的,线程由运行状态切换到等待状态,此时cpu会做上下文切换,以便处理其他的程序;当I/O操作完成后,cpu出收到一个来自硬盘的中断信号,并进入中断处理例程,手头正在执行的线程因此被打断,回到ready对列。而先前因I/O而waiting的线程随着I/O的完成也再次回到就绪队列,这时cpu可能会选择它来执行。
    如果所有的任务都是计算密集型的,则创建的多线程数=处理器核心说就可以了,如果io操作比较耗时,则根据具体情况调整线程数,此时 多线程数=n*处理器核心数 一般情况程序线程数等于cpu线程数的两到三倍就能很好的利用cpu了,过多的程序线程数不但不会提高性能,反而还会因为线程间的频繁切换而受影响,具体需要根据线程处理的业务考虑,不断调整 线程数个数,确定当前系统最优的线程数。

    更多相关内容
  • java线程数过高原因分析

    千次阅读 2017-07-31 11:21:13
    前阵子我们因为B机房故障,将所有的流量切到了A机房,在经历了推送+自然高峰之后,A机房所有服务器都出现java线程数接近1000的情况(1000是设置的max值),在晚上7点多观察,java线程数略有下降,但还是有900+的样子...

    一、问题描述

    前阵子我们因为B机房故障,将所有的流量切到了A机房,在经历了推送+自然高峰之后,A机房所有服务器都出现java线程数接近1000的情况(1000是设置的max值),在晚上7点多观察,java线程数略有下降,但还是有900+的样子,而此时,单台服务器的TPS维持在400/s,并不是一个特别大的量。然后将A机房一台机器下线,继续观察,到了晚上9点多,那台下线的机器,jetty进程的java线程数还是7、800的样子。同时,同一机房的另外一台还在线的机器在重启jetty之后,在同样tps400+的情况,线程数一直保持在只有300多。这就很奇怪了,下线的机器都没有请求了,java线程数怎么还是这么多?会不会是多线程竞争资源,导致阻塞?开始研究这个问题。

    二、保存现场

    保存哪些现场

    我先查看并记录了当时的jetty进程的线程数、db连接数、cpu负载、内存使用情况、tps、nginx连接数、jetty错误日志、GC情况、tcp连接状态等,都是正常。
    然后我用jstack命令导出当前jvm的所有线程快照,用jmap命令将当前java堆转储快照导出,结果发现,除了java线程数之外,其他指标也都是正常。
    这里先说下jstack和jmap使用的常用参数举例和注意事项:

    找到jetty进程pid

    对于这两个命令,首先都需要找出jetty进程对应的pid,当然可以使用jps命令来查找对应的pid。
    但是,我当前linux用户是自己的用户名用户,而公司外网服务器我并没有jetty的权限,也就是说jps命令只有jetty用户可以查看。
    在网上找了下资料,这里我采用的是这种方式,用ps aux|grep jetty.xml找到了jetty进程对应的pid。

    jstack保存线程快照

    我使用jstack完整命令是:“sudo -u jetty /data/java/bin/jstack -l pid >> ~/jstack.txt”。-l 参数是将锁的信息也打印出来。
    这里,有个比较隐蔽的坑,我们的jetty进程是jetty用户的。如果在linux上是root用户或者其他用户直接执行jstack -l pid,会出现报错。所以,需要在命令前加上sudo -u jetty,用jetty账户来执行这个命令。
    而jetty账户又不一定将/data/java/bin加入环境变量,所以需要执行jstack的完整路径。
    执行完毕的结果存放在home目录下的jstack.txt文件中。(这里是找运维同事协助完成的)

    jmap保存堆转储快照

    同样,jmap命令也需要注意命令执行的用户。我使用的完整命令是:“sudo -u jetty /data/java/bin/jmap -dump:format=b,file=~/jmap.hprof   pid”。
    导出来的hprof文件非常大,保存了当时堆中对象的快照。hprof不能直接阅读,需要用专门的工具来分析。最常用的是mat和jhat。mat是图形界面的工具,有windows版的,比较方便。但是mat有个死穴,当分析的hprof文件过大时,会出现内存溢出的错误而导致无法得到结果。我曾经尝试解决这个问题,但是一直没有找到有效的方法。所以这里我用的是jhat。

    jhat分析堆转储快照

    jhat是java自带的命令行工具,比较简朴。但是对于特别大的文件,好像是唯一的选择。将hprof文件压缩,下载到开发环境的虚拟机上,就可以开始用jhat分析了。
    我使用的完整命令是:“jhat -J-d64 -J-mx9g -port 5000 jmap.hprof”。来解释一下参数。-J-d64:因为jetty进程是在64位的系统上运行,所以需要指定64位。-J-mx9g:表示jhat进程最多可以分配9G的堆内存,这就是为什么jhat可以分析超大文件的原因了,因为可以指定堆内存大小。-port 5000:jhat分析完毕之后,会启动一个web服务,可以通过指定端口来访问,这就是指定的端口。
     
    参数就介绍完了,但是这样的命令会有一个问题。上面的命令执行完,jhat进程是在前台的。换句话说,如果你ctrl+c(或者xshell连接超时)结束了这个前台进程,那么jhat提供的web服务就结束了,你刚才分析了那么久的文件得重新再来。解决这个问题,用到linux上的nohup和&组合。通过命令“nohup jhat -J-d64 -J-mx9g -port 5000 jmap.hprof & ”,就可以将进程放到后台执行。有兴趣可以研究一下nohup,在这里不做赘述。
     
    jhat分析需要一定时间。可以用top命令看,当jhat进程没有疯狂的吃cpu的时候,说明分析已经结束了。此时,可以通过ip:port来访问刚才分析出的结果了。

    三、定位问题

    首先,来看刚才的jstack.txt。
    在近900个线程里面,有600+个线程都是wait在同一个对象<0x0000000734afba50>上,而且这600+个线程的调用栈都是一模一样的。去查了一下,这个org.eclipse.jetty.util.thread.QueuedThreadPool的作用,就是jetty的worker线程池。每当一个请求来临的时候,jetty就从这个QueuedThreadPool中新建一个线程或者取一个空闲线程来处理这个请求。
    看到调用栈里面的“at org.eclipse.jetty.util.thread.QueuedThreadPool.idleJobPoll(QueuedThreadPool.java:526)”,感觉好像这些线程都在等待任务来处理。当然,这是猜的。
    为了验证这个猜想,找到刚才jhat已经分析好的堆的快照结果。首先,我找到“class org.eclipse.jetty.util.thread.QueuedThreadPool ”这个类,然后依次点击,进入到QueuedThreadPool的唯一的实例中。

    到这里,就可以看到QueuedThreadPool这个对象中所有成员变量了:

     
    其中,有两个AtomicInteger型变量在这里需要关心:_threadsStarted和_threadsIdle。
    _threadsStarted表示QueuedThreadPool当前拥有的线程数,而_threadsIdle表示QueuedThreadPool中空闲的线程数。
    点击进去,就看到这两个成员变量的值,value分别是707和613。
    这表示,QueuedThreadPool当前开启了707个用于处理用户请求的线程,而其中有613个处于闲置状态。
      到这里,我们上面的猜想基本得到验证。那些大量的time_wait的线程,真的是处在等待请求到来的状态。那么问题是,既然是闲置的线程,为什么jetty没有进行回收,time_wait有这么长时间吗?

    四、分析jetty源码,确定原因

    要继续确定为什么空闲线程没有被回收原因,分析jetty源码是一种思路。我只找到和线上jetty大版本一样,小版本接近的jetty源码。但是不妨碍理清这部分的逻辑。
    继续回到刚才的jstack的结果中:
    熟悉阻塞队列的人都知道,栈中的“org.eclipse.jetty.util.BlockingArrayQueue.poll(BlockingArrayQueue.java:342) ”,就是从一个指定的阻塞队列中去获取任务。如果此时阻塞队列中没有任务可取,线程就会被阻塞住,直到队列中有任务可取或者超时。如果超时,poll方法将返回null值。进入到idleJobPoll()方法中,也很容易就发现,poll的超时时间也是用了刚才的_maxIdleTimeMs变量,也就是60s。所以才会发生600+个线程同时wait一个条件的情况。这些线程都在等待BlockingArrayQueue中任务来临这个Condition。那么,是谁让线程调用poll的?为什么poll设置了超时时间,在超时之后,线程没有结束呢?为什么这些空闲线程没有被及时回收呢?
    带着这些问题,我们来看QueuedThreadPool的源码。我们直接找到调用了idelJobPoll()方法的这块代码,如下:
    这里有几个变量和方法需要先说明一下。_maxIdelTimeMs是QueuedThreadPool中的一个成员变量,表示超时的毫秒数,默认值是60000(表示60秒),可以在刚才jhat分析的结果中查询到这个值。_lastShrink也是QueuedThreadPool的一个成员变量,是线程安全的AtomicLong类型,表示上一次线程退出时的时间戳,被所有线程池中的线程共享。campareAndSet方法,就是著名的CAS(比较后赋值)。例如:_lastShrink.compareAndSet(last,now)的意思是,先将_lastShrink和last比较看是否相同,相同则将_lastShrink的值等于now并返回true,否则不进行赋值并返回false。
    当一个空闲线程从idelJobPool()方法中超时后获取到null值,会再次进入while循环。此时的线程数size(700+)是要大于_minThreads(设置的为200),所以会进入框中的if代码块。if代码块中主要经历了以下步骤:

    1.将last赋值为上一个线程池中的线程退出时的时间戳,将当前时间赋值给now。

    2.然后“if (last==0 || (now-last)>_maxIdleTimeMs)”这一句判断,now距离上一个线程退出是否超过了maxIdleTimeMs(60000,60秒)。

    3.如果2步骤中条件成立,会对_lastShrink重新赋值为当前时间,并将QueuedThreadPool中的线程计数减一。

    campareAndSet保证了,每一次只会有一个线程能够赋值成功。

    赋值成功后,就会return,让线程跳出while循环,这个线程就结束了。

    对于赋值不成功的线程,会继续执行到idleJobPoll(),和步骤4相似。

    4.如果2步骤中条件不成立,会重新回到idleJobPoll(),阻塞住线程,又会尝试从阻塞队列中获取任务。

    也就是说,每当一个空闲线程执行到框中的代码时,都要判断现在距离上次有线程退出是否超过60s。如果没有超过60s,这个线程会继续回到idelJobPool方法中去等待任务。换句话说,1分钟之内,QueuedThreadPool最多只能允许一个线程退出。那么,我们600+个空闲线程如果要全部退出,那就要600分钟,也就是10个小时!!
    难怪,会有那么多空闲线程在那里啊,虽然这些空闲线程可以被重复利用并不影响业务,但也是占用了线程资源。不知道这个算不算是个bug,但是真的很坑。由其影响通过java线程数去判断业务的繁忙情况,容易受到误导。

    五、实验验证

    为了进一步验证这个结论,我在开发环境部署了一样的业务,纯净且没有其他人访问。用ab以1000并发量发起30000个请求,迅速将java线程数提升至1000(最大值)。然后用watch命令,每5分钟观察一次java线程数,下面是部分结果:

    可以看到,每5分钟,线程数都下降了5。确实是1分钟退出一个线程啊!
    展开全文
  • 查看java线程

    千次阅读 2020-02-16 14:43:53
    我们知道java线程使用的是底层操作系统"轻量级线程"+"内核线程"的1:1模型,那么我们如何查看一个运行的java进程中线程数呢? 1、linux上查看进程中线程数: 主要有以下三种方法: 1)top -Hp pid $ top -Hp ...

    我们知道java线程使用的是底层操作系统"轻量级线程"+"内核线程"的1:1模型,那么我们如何查看一个运行的java进程中线程数呢?

    1、linux上查看进程中线程数:

    主要有以下三种方法:

    1)top -Hp pid

    $ top -Hp 12121
    top - 13:37:23 up 223 days, 18:41,  2 users,  load average: 0.01, 0.02, 0.05
    Threads:  20 total,   0 running,  20 sleeping,   0 stopped,   0 zombie
    %Cpu(s):  0.1 us,  0.2 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem : 16267876 total,   549064 free,  3220720 used, 12498092 buff/cache
    KiB Swap:  2097148 total,  2034684 free,    62464 used. 11924764 avail Mem 
    
      PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                  
    12121 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12122 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.10 java                                     
    12123 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12124 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12125 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12126 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12127 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12128 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12129 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12130 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12131 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12132 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12133 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12134 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12135 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12136 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12137 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12138 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12139 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12140 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.03 java    

    2)cat /proc/pid/status | grep Thread

    $ cat /proc/12121/status | grep Thread
    Threads: 20

    3)pstree -p pid:

    $ pstree -p 12121
    java(12121)─┬─{java}(12122)
                ├─{java}(12123)
                ├─{java}(12124)
                ├─{java}(12125)
                ├─{java}(12126)
                ├─{java}(12127)
                ├─{java}(12128)
                ├─{java}(12129)
                ├─{java}(12130)
                ├─{java}(12131)
                ├─{java}(12132)
                ├─{java}(12133)
                ├─{java}(12134)
                ├─{java}(12135)
                ├─{java}(12136)
                ├─{java}(12137)
                ├─{java}(12138)
                ├─{java}(12139)
                └─{java}(12140)

    注:上述三种方法得到的结果都是一致的。

    2、通过java api打印java中的线程:

    import java.lang.management.ManagementFactory;
    import java.lang.management.ThreadInfo;
    import java.lang.management.ThreadMXBean;
    
    public class Test1 {
    	public static void main(String[] args) {
    		ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
    		ThreadInfo[] threadInfo = threadBean.dumpAllThreads(false, false);
    		for(ThreadInfo info : threadInfo){
                System.out.println(info.getThreadId() + "--" + info.getThreadName() +"--"+ info.getThreadState().name());
            }
    	}
    }
    

    输出结果:

    4--Signal Dispatcher--RUNNABLE

    3--Finalizer--WAITING

    2--Reference Handler--WAITING

    1--main--RUNNABLE

    说明:虽然我们写了一个main函数的单线程程序,但是JVM会启动一些额外的线程,主要包括:

    • Attach Listener 线程:负责接收外部JVM的命令,而对该命令进行执行的,并且把结果返回给发送者。如常用的命令:java -version、jmap、jstack等
    • Signal Dispatcher 线程:Attach Listener线程接收到命令后,会交给Signal Dispatcher线程去进行分发到各个不同的模块处理命令,并且返回处理结果
    • Finalizer 线程:在垃圾回收之前执行“对象完成”的Java系统线程
    • Reference Handler  线程:处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题

    注意:Attach Listener、Signal Dispatcher线程在jvm启动的时候若没有初始化,那么则会在用户第一次执行jvm命令时启动这两个线程。

    3、实战示例:

    1)我们写一个main线程的(单线程)程序:

    public class Test2 {
    	public static void main(String[] args) throws Exception {
    		while(true) {
    			Thread.sleep(2000);
        		System.out.println("main...");
    		}
    	}
    }
    

    2)运行后,使用上面的方法查看该java进程的线程数:

    $ top -Hp 12121
    top - 13:37:23 up 223 days, 18:41,  2 users,  load average: 0.01, 0.02, 0.05
    Threads:  20 total,   0 running,  20 sleeping,   0 stopped,   0 zombie
    %Cpu(s):  0.1 us,  0.2 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem : 16267876 total,   549064 free,  3220720 used, 12498092 buff/cache
    KiB Swap:  2097148 total,  2034684 free,    62464 used. 11924764 avail Mem 
    
      PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                  
    12121 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12122 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.10 java                                     
    12123 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12124 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12125 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12126 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12127 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12128 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12129 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12130 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12131 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12132 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12133 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12134 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12135 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12136 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12137 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12138 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12139 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.00 java                                     
    12140 root      20   0 6963564  26104  10532 S  0.0  0.2   0:00.03 java    

    可以看到该java进程包含了20个线程(使用另外的两种方法得到同样的结果)。这里有个问题,为什么会有这么多线程呢?

    3)使用jstack查看线程详情:

    $ jstack -l 12121
    2020-02-16 13:39:26
    Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode):
    
    "Attach Listener" #10 daemon prio=9 os_prio=0 tid=0x00002b9ad4001000 nid=0x3c78 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
       Locked ownable synchronizers:
    	- None
    
    "Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00002b9a800d2000 nid=0x2f6b runnable [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
       Locked ownable synchronizers:
    	- None
    
    "C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00002b9a800c7000 nid=0x2f6a waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
       Locked ownable synchronizers:
    	- None
    
    "C2 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00002b9a800c4800 nid=0x2f69 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
       Locked ownable synchronizers:
    	- None
    
    "C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00002b9a800c3000 nid=0x2f68 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
       Locked ownable synchronizers:
    	- None
    
    "C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00002b9a800c0000 nid=0x2f67 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
       Locked ownable synchronizers:
    	- None
    
    "Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00002b9a800be800 nid=0x2f66 runnable [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
       Locked ownable synchronizers:
    	- None
    
    "Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00002b9a8008b800 nid=0x2f65 in Object.wait() [0x00002b9abd8be000]
       java.lang.Thread.State: WAITING (on object monitor)
    	at java.lang.Object.wait(Native Method)
    	- waiting on <0x000000076d408ec8> (a java.lang.ref.ReferenceQueue$Lock)
    	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    	- locked <0x000000076d408ec8> (a java.lang.ref.ReferenceQueue$Lock)
    	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
    
       Locked ownable synchronizers:
    	- None
    
    "Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00002b9a80086800 nid=0x2f64 in Object.wait() [0x00002b9abd7bd000]
       java.lang.Thread.State: WAITING (on object monitor)
    	at java.lang.Object.wait(Native Method)
    	- waiting on <0x000000076d406b68> (a java.lang.ref.Reference$Lock)
    	at java.lang.Object.wait(Object.java:502)
    	at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    	- locked <0x000000076d406b68> (a java.lang.ref.Reference$Lock)
    	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
    
       Locked ownable synchronizers:
    	- None
    
    "main" #1 prio=5 os_prio=0 tid=0x00002b9a80008800 nid=0x2f5a waiting on condition [0x00002b9a7b9c6000]
       java.lang.Thread.State: TIMED_WAITING (sleeping)
    	at java.lang.Thread.sleep(Native Method)
    	at Test2.main(Test2.java:5)
    
       Locked ownable synchronizers:
    	- None
    
    "VM Thread" os_prio=0 tid=0x00002b9a8007f000 nid=0x2f63 runnable 
    
    "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00002b9a8001d800 nid=0x2f5b runnable 
    
    "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00002b9a8001f800 nid=0x2f5c runnable 
    
    "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00002b9a80021000 nid=0x2f5d runnable 
    
    "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00002b9a80023000 nid=0x2f5e runnable 
    
    "GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00002b9a80025000 nid=0x2f5f runnable 
    
    "GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00002b9a80026800 nid=0x2f60 runnable 
    
    "GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00002b9a80028800 nid=0x2f61 runnable 
    
    "GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00002b9a8002a800 nid=0x2f62 runnable 
    
    "VM Periodic Task Thread" os_prio=0 tid=0x00002b9a800d5000 nid=0x2f6c waiting on condition 
    
    JNI global references: 6

    在thread dump中每个线程都有一个nid(十六进制),该进成共有20个nid(线程)。主要包括:

    • Attach Listener、Signal Dispatcher、Finalizer、Reference Handler
    • GC task thread:gc线程
    • C1 CompilerThread:C1即时编译线程;
    • C2 CompilerThread:C2即时编译线程;
    • main:用户线程

    4)修改java代码,添加一个线程:

    public class Test {
    
    	public static void main(String[] args) throws Exception {
    		System.out.println("main...");
    
    		
    		new Thread() {
    			public void run() {
    				while(true) {
    					try {
    						Thread.sleep(1000);
    						System.out.println("test1...");
    					} catch(Exception e) {
    
    					}
    				}
    			}
    		}.start();
    		new Thread() {
    			public void run() {
    				while(true) {
    					try {
    						Thread.sleep(1000);
    						System.out.println("test2...");
    					} catch(Exception e) {
    
    					}
    				}
    			}
    		}.start();
    	}
    }
    

    一共起了有3个线程(算main线程)。接下来我们运行该程序,并使用top查看该进程中的线程数。

    $ top -Hp 11444
    top - 14:05:29 up 223 days, 19:09,  2 users,  load average: 0.00, 0.01, 0.05
    Threads:  22 total,   0 running,  22 sleeping,   0 stopped,   0 zombie
    %Cpu(s):  0.0 us,  0.1 sy,  0.0 ni, 99.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem : 16267876 total,   537252 free,  3222404 used, 12508220 buff/cache
    KiB Swap:  2097148 total,  2034684 free,    62464 used. 11914756 avail Mem 
    
      PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                  
    11444 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11445 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.09 java                                     
    11447 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11448 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11449 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11450 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11451 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11452 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11453 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11454 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11466 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11473 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11477 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11487 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11488 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11489 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11490 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11491 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11492 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11493 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11494 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java                                     
    11495 root      20   0 7096692  26292  10624 S  0.0  0.2   0:00.00 java  

     

    我们看到一共有22个线程,比之前的单线程程序多了两个我们自定义的线程。使用jstack查看可以发现多了如下两个线程信息:

    "Thread-1" #11 prio=5 os_prio=0 tid=0x00002adca410a000 nid=0x2ce7 waiting on condition [0x00002adce1715000]
       java.lang.Thread.State: TIMED_WAITING (sleeping)
    	at java.lang.Thread.sleep(Native Method)
    	at Test$2.run(Test.java:24)
    
       Locked ownable synchronizers:
    	- None
    
    "Thread-0" #10 prio=5 os_prio=0 tid=0x00002adca4108000 nid=0x2ce6 waiting on condition [0x00002adce1614000]
       java.lang.Thread.State: TIMED_WAITING (sleeping)
    	at java.lang.Thread.sleep(Native Method)
    	at Test$1.run(Test.java:12)
    
       Locked ownable synchronizers:
    	- None
    

     

    展开全文
  • cpu个数、核数、线程数Java多线程关系的理解

    万次阅读 多人点赞 2017-12-08 15:35:37
    一 cpu个数、核数、线程数的关系 cpu个数:是指物理上,也及硬件上的核心...二 cpu线程数Java多线程 首先明白几个概念: (1) 单个cpu线程在同一时刻只能执行单一指令,也就是一个线程。 (2) 单个线程同时只能...

    一 cpu个数、核数、线程数的关系

    cpu个数:是指物理上,也及硬件上的核心数;

    核数:是逻辑上的,简单理解为逻辑上模拟出的核心数;

    线程数:是同一时刻设备能并行执行的程序个数,线程数=cpu个数 * 核数【如果有超线程,再乘以超线程数】

    二 cpu线程数和Java多线程

    首先明白几个概念:

    (1) 单个cpu线程在同一时刻只能执行单一指令,也就是一个线程。

    (2) 单个线程同时只能在单个cpu线程中执行。

    (3) 线程是操作系统最小的调度单位,进程是资源(比如:内存)分配的最小单位。

    (4)Java中的所有线程在JVM进程中,CPU调度的是进程中的线程。

    (5)Java多线程并不是由于cpu线程数为多个才称为多线程,当Java线程数大于cpu线程数,操作系统使用时间片轮转(RR)调度算法,频繁的进行上下文切换,以便并发执行其他线程。

    (6)cpu执行Java程序,其根本是执行java代码编译后的操作系统可以识别的指令,cpu执行一条指令的时间是ns级别的(1.6G的cpu执行一条指令,大概需要0.6ns),而cpu上下文切换则需要5000-10000个CPU时钟周期。

    (7)受内核限制,Linux系统单个进程最多开启1000个线程,Windows系统单个进程最多开启2000个线程。

    (8)默认情况下,Java中每创建一个线程,操作系统会分配1M的栈空间。

    a 那么java多进程,每个进程又多线程,cpu是如何调度的呢?

    个人理解:操作系统并不是单纯均匀的分配cpu执行不同的进程,因为线程是调度的最小单位,所以会根据不同进程中的线程个数进行时间分片,均匀的执行每个线程,也就是说A进程中有10个线程,而B进程中有2个线程,那么cpu分给进程的执行时间理论上应该是5:1才合理。

    b cpu线程数和java线程数有直接关系吗?

    个人理解:没有直接关系,正如上面所说,cpu采用分片机制执行线程,给每个线程划分很小的时间颗粒去执行,但是真正的项目中,一个程序要做很多的的操作,读写磁盘、数据逻辑处理、出于业务需求必要的休眠等等操作,当程序在进行I/O操作的时候,线程是阻塞的,线程由运行状态切换到等待状态,此时cpu会做上下文切换,以便处理其他的程序;当I/O操作完成后,cpu 会收到一个来自硬盘的中断信号,并进入中断处理例程,手头正在执行的线程因此被打断,回到 ready 队列。而先前因 I/O 而waiting 的线程随着 I/O 的完成也再次回到 就绪 队列,这时 cpu 可能会选择它来执行。

    c 如何确定程序最佳线程数?

    个人理解:如果所有的任务都是计算密集型的,则创建的多线程数 = 处理器核心数就可以了

                      如果io操作比较耗时,则根据具体情况调整线程数,此时 多线程数 = n*处理器核心数

            一般情况程序线程数等于cpu线程数的两到三倍就能很好的利用cpu了,过多的程序线程数不但不会提高性能,反而还会因为线程间的频繁切换而受影响,具体需要根据线程处理的业务考略,不断调整线程数个数,确定当前系统最优的线程数。

     

     

    展开全文
  • 查看电脑逻辑核心: 点"性能"选项卡,可以看到CPU使用记录,下面有几个框就代表有逻辑核心几个核心。如下图分别代表逻辑四...综上:本电脑双核四线程:cpu物理上只有两个核心,但每个核心模拟成两个...
  • 统计Java进程开启的线程数的N中方法

    万次阅读 2017-12-26 18:35:16
    引言: 在Java语言中,线程被广泛的使用,在大部分的情况下,大家其实都是不关心到底在Java Application中创建了多少个线程的,那该如何去查看进程到底启动了多少个线程呢?本文将给出若干种方法top命令 top -Hp ...
  • Java 确定线程池中工作线程数的大小

    万次阅读 2018-09-12 16:20:17
    a、服务器cpu核数有限,所以同时并发或者并行的线程数是有限的,所以1核cpu设置1000个线程是没有意义的。  b、线程切换也是有开销的。频繁切换线程会使性能降低。 2、调用sleep()函数的时候,县城是否会占用着CPU...
  • Java应用线程数每天在涨没有释放

    千次阅读 2019-05-29 16:10:28
    项目中使用到ES,使用Druid JDBC方式连接ES,因为索引时按照天的维度来创建的,查询时没有聚合 导致ES连接的线程池每天都会增加。DruidJDBC方式连接一次ES,就会创建一个线程池,每个线程池里面有64个线程。 ...
  • JAVA 线程数量如何设置

    千次阅读 2018-09-05 13:25:00
    利用率希望是100%那么也就是1,总体程序最佳的线程数应该是4*1*(1+100)=404个线程数,但实际操作中,设置404个线程明显不能带来性能的优势,这么多线程数只会增加上下文来回切换带来更严重的性能问题。 如果你的...
  • Java线程:创建多少线程才合适?

    千次阅读 2019-09-05 13:25:46
    1、线程执行 线程的执行是由CPU进行调度的,一个CPU在同一时刻只会执行一个线程 操作系统利用了时间片轮转的方式,CPU给每个任务都服务一定的时间,然后把当前任务的状态保存下来,再加载下一个任务的状态后,继续...
  • 没满,创建一个工作线程来执行任务。满了,则进入下个流程;其次线程池判断工作队列(workQueue)是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程;最后线程池判断整个线程池...
  • Java线程(第三版).pdf[带书签]

    千次下载 热门讨论 2015-02-12 17:32:23
    Java线程(第三版)》,完整版本。作者:Scott Oaks、Henry Wong,翻译:O’Reilly Taiwan 公司,出版社:东南大学出版社,ISBN:756410239X,PDF 格式,扫描版,大小 29MB。本资源带有PDF书签,方便读者朋友阅读。 ...
  • Java线程池的核心线程数和最大线程数

    千次阅读 多人点赞 2021-03-14 19:24:35
    Java的线程池就像是一个花瓶容器。 而把任务提交给线程池就像是把小球塞进花瓶。 整个过程就像下面这个有趣的动画: 下面我们先来了解一下Java线程池的参数。 希望看完这篇文章后, 再提起线程池的时候, 你脑海...
  • Java线程池核心线程数与最大线程数的区别

    万次阅读 多人点赞 2020-06-23 15:20:45
    corePoolSize:核心线程数;maximunPoolSize:最大线程数 每当有新的任务到线程池时, 第一步: 先判断线程池中当前线程数量是否达到了corePoolSize,若未达到,则新建线程运行此任务,且任务结束后将该线程保留在...
  • 摘自: Java线程池的核心线程数和最大线程数总是容易混淆怎么办
  • java 最大线程数

    万次阅读 2014-02-17 13:48:43
    工作中碰到过这个问题好几次了,觉得有必要总结一下,所以有了这篇文章,这篇文章分为三个部分:认识问题、分析问题、解决问题。   一、认识问题: ...首先我们通过下面这个 测试程序 来认识这个问题...Java代码 
  • java查看当前活动的线程数量

    千次阅读 2020-08-14 14:13:08
    Thread.activeCount() 如果不是多线程,那么至少也有两个线程,一个是main还有一个是jvm的gc线程,可以利用这个来判断多线程是否运行完成
  • java 线程 (一) 线程的简单使用

    千次阅读 2020-12-05 11:02:48
    大家好,从今天开始,我和大家一起来探讨 java线程的使用。线程java 知识体系中非常重要的一部分,我将写一系列的文章来详细的介绍 java 线程中需要掌握的知识。如果你是 java 线程的初学者,本系列文章你一定...
  • windows查看java进程和线程信息

    千次阅读 2020-09-01 19:32:08
    查看进程 pslist或 tasklist 注:若出现“pslist不是外部或内部命令,也不是可运行的程序....”,需要去TechNet官网下载psTools(链接... ...2、查看某一进程下的所有线程 pslist -dmx pid号 ...
  • java线程池合理设置最大线程数和核心线程数

    万次阅读 多人点赞 2020-10-10 17:13:31
    这个时候就需要使用多线程去处理。 一开始是这么配置的: @Configuration @EnableAsync(proxyTargetClass = true)//利用@EnableAsync注解开启异步任务支持 @ComponentScan({"com.ctfojt.auditbcarslogo.service"}) /...
  • 本文将为您提供一个教程,使您可以确定活动应用程序Java线程中保留了多少Java堆空间 。 将提供来自Oracle Weblogic 10.0生产环境的真实案例研究,以使您更好地理解分析过程。 我们还将尝试证明过多的垃圾回收或...
  • Java 查看运行程序线程数

    万次阅读 2014-07-07 15:24:44
    //获取线程数 ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); while(threadGroup.getParent() != null){ threadGroup = threadGroup.getParent(); } int totalThread = thread...
  • java线程join方法

    千次阅读 2020-04-16 23:04:39
    java线程join方法 1.join方法 ​ join方法的作用是进行线程插队,也就是说调用了join方法的线程相对于调用它的上级线程拥有跟高的执行权。调用join方法的线程的上级线程必须等待调用join方法的线程执行完成才能继续...
  • Java线程超详解

    万次阅读 多人点赞 2019-06-11 01:00:30
    随着计算机的配置越来越高,我们需要将进程进一步优化,细分为线程,充分提高图形化界面的多线程的开发。这就要求对线程的掌握很彻底。 那么话不多说,今天本帅将记录自己线程的学习。 线程的相关API //获取当前...
  • 查看java项目线程运行情况,以及总线程数 观看tomcat线程或者其他java程序线程数量以及运行情况,可以查看 jdk/bin/jvisualvm.exe当前文件是用来监控线程运行信息 有时候系统报异常:如下: java.lang....
  • Java线程Dump分析

    千次阅读 2019-10-29 08:48:43
    每一个Java虚拟机都有及时生成所有线程在某一点状态的thread-dump的能力,虽然各个 Java虚拟机打印的thread dump略有不同,但是 大多都提供了当前活动线程的快照,及JVM中所有Java线程的堆栈跟踪信息,堆栈信息一般...
  • java jvm 最大线程数设置

    万次阅读 2014-10-31 18:39:25
    最近想测试下Openfire下的最大并发,需要开大量线程来模拟客户端。对于一个JVM实例到底能开多少个线程一直心存疑惑,所以打算实际测试下,简单google了把,找到影响线程数量的因素有下面几个:   -...
  • Linux查看java进程开启的线程数量

    万次阅读 2018-11-06 09:51:00
    TOP top -H -p {pid} 我这里筛选的是java的进程对应的thread是33 PS ps huH p {pid} | wc -l 直接计数统计出来
  • ThreadPoolExecutor是JDK中的线程池实现,这个类实现了一个线程池需要的各个方法,它实现了任务提交、线程管理、监控等等方法。 来看看ThreadPoolExecutor类的构造方法源码,其他创建线程池的方法最终都会导向这个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,844,832
精华内容 737,932
关键字:

java 线程数

java 订阅