首页 > 代码库 > Java 并发编程之任务取消(九)

Java 并发编程之任务取消(九)

Jvm关闭

jvm可正常关闭也可强行关闭,正常关闭有多种触发方式:

  • 当最后一个正常(非守护,下面会讲到什么是守护线程)线程结束时
  • 当调用system.exit时,或者通过其他特定于平台的方法关闭时(例如发送了SIGINT信号或键入Ctrl-c)
  • 通过其他特定平台的方法关闭jvm,调用Runtime.halt或者在操作系统当中杀死JVM进程(例如发送sigkill)来强行关闭jvm。

关闭钩子

在正常关闭中,jvm首先调用所有已注册的关闭钩子,关闭钩子是指通过 Runtime.addShutdownHook注册的但尚未开始的线程。JVM并不能保证关闭钩子的调用顺序。在关闭应用程序线程时,是并发执行的。

当所有关闭钩子都执行结束时,如果runFinalizersOnExit为true,那么jvm将运行终结器,然后再停止。jvm并不会停止或中断任何在关闭时仍然运行的应用程序线程。

当jvm最终结束时,这些线程将被强行结束。如果关闭钩子或终结器没有执行完成,那么正常关闭进程挂起并且 jvm必须强行关闭。当被强行关闭时,只是关闭jvm。而不会运行关闭钩子。


关闭钩子应该是线程安全的,它们在访问共享数据时必须使用同步 机制,并且避免发生死锁。

而且关闭钩子不应该对应用程序的状态(如:其它服务是否已经关闭,或者 所有正常线程是否已经执行完成)或者对jvm的关闭原因做出假设。

最后,在关闭钩子时应该尽快退出,因为他们 会延迟jvm的结束时间 。



关闭钩子的应用 :实现服务或应用 程序的清理工作,例如删除临时文件等等。下面举个日志服务的栗子。

public void start() {
		Runtime.getRuntime().addShutdownHook(new Thread() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				try {
					logservice.stop();
				} catch (Exception e) {
					// TODO: handle exception
				}
			}
		});

	}

因为关闭钩子是并发执行的,所以它不应该依赖其它关闭钩子的服务。实现 这种功能的方法就是对所有服务使用同一个关闭钩子也就是说所有操作放在同一个addshutdownhook里。

守护线程

守护线程其实就是辅助线程。比如在jvm启动时创建的所有线程中,除了主线程以外,其他的线程都是守护线程(例如垃圾回收器)。默认情况下,由主线程创建的所有线程都是普通线程。同理,由守护线程创建的线程也全是守护 线程,线程之间存在继承关系


守护线程和普通线程之间的区别仅在于线程退出时发生的操作:

当一个线程退出时,jvm会检查其他正在运行的线程,如果 是守护线程,jvm会正常退出。当jvm停止时 ,所有仍然存在的守护线程都将被抛弃。不会执行finally块,也不会回卷栈。只是直接退出。


终结器

对于一些资源,如文件句柄或者套接字句柄,当不再需要他们时,必须显式的交还给操作系统,垃圾回收器会那些定义了finalize方法的对象进行特殊处理。当回收它们时会调用他们的finalize方法 。复杂的终结器会产生巨大的开销,所以应该避免使用终结器。


参考资源:《java并发编程实战》



Java 并发编程之任务取消(九)