Tomcat服务器启动后,实际有6个线程在工作,即1个用户线程(下图中的Thread[Main]),剩下5个为守护线程(下图中的Daemon Thread),分别是通过BIO。
第一个守护线程(Daemon Thread [ContainerBackgroundProcessor[StandardEngine[Catalina]]] (Running)
)是容器后台处理线程。
第二个守护线程(Daemon Thread [http-bio-8080-Acceptor-0] (Running)
)监听8080端口,负责建立HTTP连接。通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器。
第五个守护线程(Daemon Thread [ajp-bio-8009-Acceptor-0] (Running)
)监听8009端口,负责和其他的HTTP服务器建立连接。把Tomcat与其他HTTP服务器集成时就需要用到这个连接器。在Nginx出现前,Web应用动静分离使用的是Apache,Tomcat与Apache通信采用的就是AJP协议。
我们来看一下线程的属性。
http-bio-[InetAddress]-[port]-Acceptor-Number 如:默认为http-bio-8080-Acceptor-0。
1.优先级:默认优先级5
2.是否Daemon:守护线程模式运行
3.线程个数:tomcat7 默认启动1个 Acceptor线程
守护线程与用户线程没有本质区别,它们是可以相互切换的。将用户线程转换为守护线程可以通过调用Thread对象的setDaemon(true)方法来实现。不同点在于退出的时间:用户线程->守护线程->jvm。
所谓守护线程,是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程、处理GUI事件的事件调度线程等。这种线程不是不可或缺的,当所有的用户线程结束、只剩下守护线程了,程序就会自动终止。因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。反过来说,只要有任何用户线程还在运行,程序就不会终止。Tomcat的关闭正是利用了这个原理,只要将那唯一的用户线程关闭,则整个应用就关闭了。
以下代码可以验证当前用户线程只有一个,即只要main线程退出,然后JVM就真的退出了。
import java.util.Scanner;
public class DaemonThread implements Runnable {
int i = 0;
public void run() {
while (true) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
}
@SuppressWarnings("resource")
public static void main(String[] args) {
Thread daemonThread = new Thread(new DaemonThread());
// 设置为守护进程
daemonThread.setDaemon(true);
daemonThread.start();
System.out.println("isDaemon = " + daemonThread.isDaemon());
Scanner scanner = new Scanner(System.in);
// 接受输入,使程序在此停顿,一旦接受到用户输入,main线程结束,JVM退出!
scanner.next();
// AddShutdownHook方法增加JVM停止时要做处理事件:当JVM退出时,打印JVM Exit语句.
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("JVM Exit!");
}
});
}
}