线程小白入门教程,得小白者,得天下!

Java中main方法详解

Java中的main方法,是一个Java应用程序的入口,无论一个Java的应用多么复杂庞大或是多么的小,只要它是一个可以运行的Java程序,那么必然就要有一个main方法。main方法的定义格式通常固定如下:
	
public class Demo 
{
	public static void main(String[] args) 
	{
		System.out.println("Hello Word");
	}
}
	

1、为什么是公共的(public)

Java制定了一些可访问的修饰符如:private,protected,public。每个修饰符都有它对应的权限,public权限最大,为了说明问题,我们假设main方法是用private修饰的,那么main方法出了Demo这个类对外是不可见的。那么,JVM就访问不到main方法了。因此,为了保证JVM在任何情况下都可以访问到main方法,就用public修饰。

2、为什么是静态的(static)

静态可以让JVM调用main方法的时候更加方便,不需要通过对象调用。static关键字修饰的方法,可以不用通过创建一个实例去访问,而是可以通过类名直接访问。并且static修饰的方法以及变量存储在虚拟机当中的方法区当中,而非堆内存当中。那么,对于虚拟机来说也是一样的道理。main方法定义为static的,则对于虚拟机来说,在程序启动之后并不需要创建一个实例,就可以去调用这个main方法。

3、为什么没有返回值(void)

void表示main方法没有返回值,没有返回值的原因是因为Java不需要main方法向操作系统返回退出信息。如果main方法正常退出,那么Java应用层序的退出代码为0,表示成功的运行了程序。

4、main

main的名称不能变是为了JVM能够识别程序运行的起点,main方法可以被重载,重载的main方法不会被执行。main方法作为程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程,非守护线程和守护线程,main方法属于非守护线程,守护线程通常由JVM自己使用,Java程序也可以表明自己的线程是守护线程。当程序中所有的非守护线程终止时,JVM退出。也可以用Runtime类或者System.exit()来退出。

5、String [] args

String[] args,是main方法中唯一可以改变的地方!args是arguments的缩写,只是一个变量默认名,习惯性写作它,但是也可以改变的,只要符合命名规则随便你写成什么。在使用集成开发工具的今天,String[] args更像是一种摆设了,很多初学者都不知道它的作用,其实它是程序运行传入的一个参数组。

6、Java程序运行的时候至少会启动几个线程

要想弄明白到底有几个线程会被启动,最佳的方法是自己动手实践。


public class ThreadNumDemo
{
	public static void main(String[] args)
	{
		ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
		ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
		for (ThreadInfo threadInfo : threadInfos)
		{
			System.out.println(threadInfo.getThreadId() + "-" + threadInfo.getThreadName());
		}
	}
}

运行结果为:


5-Attach Listener
4-Signal Dispatcher
3-Finalizer
2-Reference Handler
1-main

一个简单Java程序至少开了5个线程:

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

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

Finalizer线程:这个线程也是在main线程之后创建的,其优先级为10,主要用于在垃圾收集前,调用对象的finalize()方法。关于Finalizer线程的几点:
(1)只有当开始一轮垃圾收集时,才会开始调用finalize()方法;因此并不是所有对象的finalize()方法都会被执行;
(2)该线程也是daemon线程,因此如果虚拟机中没有其他非daemon线程,不管该线程有没有执行完finalize()方法,JVM也会退出;
(3) JVM在垃圾收集时会将失去引用的对象包装成Finalizer对象(Reference的实现),并放入ReferenceQueue,由Finalizer线程来处理;最后将该Finalizer对象的引用置为null,由垃圾收集器来回收;
(4) JVM为什么要单独用一个线程来执行finalize()方法呢?如果JVM的垃圾收集线程自己来做,很有可能由于在finalize()方法中误操作导致GC线程停止或不可控,这对GC线程来说是一种灾难;

Reference Handler线程:JVM在创建main线程后就创建Reference Handler线程,其优先级最高,为10,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题。

参考更多链接:main 详细介绍