欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JVM 自带线程

程序员文章站 2022-07-14 12:28:38
...

一个JVM 启动之后,自己会启动一些线程。我们在jstack的时候可以排除掉这些。只关注我们自己业务产生的线程

代码

package com.cases;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.util.List;
import java.util.Map;

public class Gouzi {

	public static void main(String[] args) {
		jvmExitHook();

		System.out.println("aaaa");
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.exit(0);
	}

	public static void jvmExitHook() {
		System.out.println("注册JVM Shutdown钩子方法---------");
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				MemoryMXBean memorymbean = ManagementFactory.getMemoryMXBean();
				System.out.println("堆内存信息: " + memorymbean.getHeapMemoryUsage());
				System.out.println("非堆内存信息: " + memorymbean.getNonHeapMemoryUsage());
				Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();

				List<GarbageCollectorMXBean> list = ManagementFactory.getGarbageCollectorMXBeans();
				if (list != null && list.size() > 0) {
					for (GarbageCollectorMXBean gcBean : list) {
						System.out.println("垃圾收集器:" + gcBean.getName());
						System.out.println("gc count:" + gcBean.getCollectionCount());
						System.out.println("gc time:" + gcBean.getCollectionTime());
						gcBean.getCollectionCount();
					}
				}

				for (Thread t : map.keySet()) {
					System.out.println("线程名称:" + t.getName() + ",线程堆栈:");
					StackTraceElement[] ss = map.get(t);
					if (ss != null) {
						for (StackTraceElement s : ss) {
							System.out.println(s);
						}
					}
				}
			}

		});
	}
}

 

 

输出结果

 

注册JVM Shutdown钩子方法---------

aaaa

内存信息: init = 16777216(16384K) used = 560368(547K) committed = 16252928(15872K) max = 259522560(253440K)

未使用内存信息: init = 35815424(34976K) used = 13675040(13354K) committed = 36110336(35264K) max = 123731968(120832K)

垃圾收集器:Copy

gc count:0

gc time:0

垃圾收集器:MarkSweepCompact

gc count:0

gc time:0

线程名称:Attach Listener,线程堆栈:

线程名称:Finalizer,线程堆栈:

java.lang.Object.wait(Native Method)

java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)

java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)

java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:171)

线程名称:Signal Dispatcher,线程堆栈:

线程名称:Reference Handler,线程堆栈:

java.lang.Object.wait(Native Method)

java.lang.Object.wait(Object.java:485)

java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)

线程名称:Thread-0,线程堆栈:

java.lang.Thread.dumpThreads(Native Method)

java.lang.Thread.getAllStackTraces(Thread.java:1530)

com.cases.Gouzi$1.run(Gouzi.java:32)

线程名称:main,线程堆栈:

java.lang.Object.wait(Native Method)

java.lang.Thread.join(Thread.java:1186)

java.lang.Thread.join(Thread.java:1239)

java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:79)

java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:24)

java.lang.Shutdown.runHooks(Shutdown.java:79)

java.lang.Shutdown.sequence(Shutdown.java:123)

java.lang.Shutdown.exit(Shutdown.java:168)

java.lang.Runtime.exit(Runtime.java:90)

java.lang.System.exit(System.java:904)

com.cases.Gouzi.main(Gouzi.java:21)

 

上边main线程和Thread-0是我启动的

 

Attach Listener

Finalizer

Signal Dispatcher

Reference Handler

是JVM 启动的

 

下边做一个解释:

 

Attach Listener :线程是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。

 

signal dispather: 前面我们提到第一个Attach Listener线程的职责是接收外部jvm命令,当命令接收成功后,会交给signal dispather线程去进行分发到各个不同的模块处理命令,并且返回处理结果。signal dispather线程也是在第一次接收外部jvm命令时,进行初始化工作。

 

Finalizer:  用来执行所有用户Finalizer 方法的线程

 

Reference Handler :它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题。

 

 

在一些其他场景Jvm会启动更多的线程,可以参考:http://club.alibabatech.org/article_detail.htm?articleId=4