shopex网站,平台式网站模板下载,婚纱摄影网站html,怎么在凡科上做网站参考链接#xff1a; Java中的JVM的关闭挂钩
1 JDK中Runtime的定义 http://blog.csdn.net/lysnow_oss/archive/2007/05/12/1606349.aspx 转载 那就首先说点Runtime类吧#xff0c;他是一个与JVM运行时环境有关的类#xff0c;这个类是Singleton的。我…参考链接 Java中的JVM的关闭挂钩
1 JDK中Runtime的定义 http://blog.csdn.net/lysnow_oss/archive/2007/05/12/1606349.aspx 转载 那就首先说点Runtime类吧他是一个与JVM运行时环境有关的类这个类是Singleton的。我说几个自己觉得重要的地方。 1、Runtime.getRuntime()可以取得当前JVM的运行时环境这也是在Java中唯一一个得到运行时环境的方法。 2、Runtime上其他大部分的方法都是实例方法也就是说每次进行运行时调用时都要用到getRuntime方法。 3、Runtime中的exit方法是退出当前JVM的方法估计也是唯一的一个吧因为我看到System类中的exit实际上也是通过调用 Runtime.exit()来退出JVM的这里说明一下Java对Runtime返回值的一般规则后边也提到了0代表正常退出非0代表异常中 止这只是Java的规则在各个操作系统中总会发生一些小的混淆。 4、Runtime.addShutdownHook()方法可以注册一个hook在JVM执行shutdown的过程中方法的参数只要是一个初始化过但是没有执行的Thread实例就可以。注意Java中的Thread都是执行过了就不值钱的哦 5、说到addShutdownHook这个方法就要说一下JVM运行环境是在什么情况下shutdown或者abort的。文档上是这样写 的当最后一个非精灵进程退出或者收到了一个用户中断信号、用户登出、系统shutdown、Runtime的exit方法被调用时JVM会启动 shutdown的过程在这个过程开始后他会并行启动所有登记的shutdown hook注意是并行启动这就需要线程安全和防止死锁。当shutdown过程启动后只有通过调用halt方法才能中止shutdown的过程并退 出JVM。 那什么时候JVM会abort退出那首先说明一下abort退出时JVM就是停止运行但并不一定进行shutdown。这只有JVM在遇到 SIGKILL信号或者windows中止进程的信号、本地方法发生类似于访问非法地址一类的内部错误时会出现。这种情况下并不能保证shutdown hook是否被执行。 首先讲的是 Runtime.exec() 方法的所有重载。这里要注意的有一点就是 public Process exec(String [] cmdArray, String [] envp); 这个方法中 cmdArray 是一个执行的命令和参数的字符串数组数组的第一个元素是要执行的命令往后依次都是命令的参数 envp 我个人感觉应该和 C 中的 execve 中的环境变量是一样的 envp 中使用的是 namevalue 的方式。 2 Runtime的构造函数和方法 Runtime是个单例类 方法摘要 void addShutdownHook 注册新的虚拟机来关闭挂钩。 ( Thread hook) int availableProcessors 向 Java 虚拟机返回可用处理器的数目。 () Process exec 在单独的进程中执行指定的字符串命令。 ( String command) Process exec 在单独的进程中执行指定命令和变量。 ( String [] cmdarray) Process exec 在指定环境的独立进程中执行指定命令和变量。 ( String [] cmdarray, String [] envp) Process exec 在指定环境和工作目录的独立进程中执行指定的命令和变量。 ( String [] cmdarray, String [] envp, File dir) Process exec 在指定环境的单独进程中执行指定的字符串命令。 ( String command, String [] envp) Process exec 在有指定环境和工作目录的独立进程中执行指定的字符串命令。 ( String command, String [] envp, File dir) void exit 通过启动虚拟机的关闭序列终止当前正在运行的 Java 虚拟机。 (int status) long freeMemory 返回 Java 虚拟机中的空闲内存量。 () void gc 运行垃圾回收器。 () InputStream getLocalizedInputStream 已过时。 从 JDK 1.1 开始将本地编码字节流转换为 Unicode 字符流的首选方法是使用 InputStreamReader 和 BufferedReader 类。 ( InputStream in) OutputStream getLocalizedOutputStream 已过时。 从 JDK 1.1 开始将 Unicode 字符流转换为本地编码字节流的首选方法是使用 OutputStreamWriter、BufferedWriter 和 PrintWriter 类。 ( OutputStream out) static Runtime getRuntime 返回与当前 Java 应用程序相关的运行时对象。 () void halt 强行终止目前正在运行的 Java 虚拟机。 (int status) void load 加载作为动态库的指定文件名。 ( String filename) void loadLibrary 加载具有指定库名的动态库。 ( String libname) long maxMemory 返回 Java 虚拟机试图使用的最大内存量。 () boolean removeShutdownHook 取消注册某个先前已注册的虚拟机关闭挂钩。 ( Thread hook) void runFinalization 运行挂起 finalization 的所有对象的终止方法。 () static void runFinalizersOnExit 已过时。 此方法本身具有不安全性。它可能对正在使用的对象调用终结方法而其他线程正在操作这些对象从而导致不正确的行为或死锁。 (boolean value) long totalMemory 返回 Java 虚拟机中的内存总量。 () void traceInstructions 启用禁用指令跟踪。 (boolean on) void traceMethodCalls 启用禁用方法调用跟踪。 (boolean on) 3 Runtime的使用 这个程序用exec调用了一个外部命令之后马上使用exitValue就对其返回值进行检查让我们看看会出现什么问题。 import java.util.*; import java.io.*; public class BadExecJavac { public static void main(String args[]) { try { Runtime rt Runtime.getRuntime(); Process proc rt.exec(javac); int exitVal proc.exitValue(); System.out.println(Process exitValue: exitVal); } catch (Throwable t) { t.printStackTrace(); } } } A run of BadExecJavac produces: E:classescomjavaworldjpitfallsarticle2java BadExecJavac java.lang.IllegalThreadStateException: process has not exited at java.lang.Win32Process.exitValue(Native Method) at BadExecJavac.main(BadExecJavac.java:13) 这里看原文就可以了解这里主要的问题就是错误的调用了exitValue来取得外部命令的返回值呵呵这个错误我也曾经犯过因为 exitValue这个方法是不阻塞的程序在调用这个方法时外部命令并没有返回所以造成了异常的出现这里是由另外的方法来等待外部命令执行完毕的就 是waitFor方法这个方法会一直阻塞直到外部命令执行结束然后返回外部命令执行的结果作者在这里一顿批评设计者的思路有问题呵呵反正我是无 所谓阿能用就可以拉。但是作者在这里有一个说明就是exitValue也是有好多用途的。因为当你在一个Process上调用waitFor方法时 当前线程是阻塞的如果外部命令无法执行结束那么你的线程就会一直阻塞下去这种意外会影响我们程序的执行。所以在我们不能判断外部命令什么时候执行完 毕而我们的程序还需要继续执行的情况下我们就应该循环的使用exitValue来取得外部命令的返回状态并在外部命令返回时作出相应的处理。 2、对exitValue处改进了的程序 import java.util.*; import java.io.*; public class BadExecJavac2 { public static void main(String args[]) { try { Runtime rt Runtime.getRuntime(); Process proc rt.exec(javac); int exitVal proc.waitFor(); System.out.println(Process exitValue: exitVal); } catch (Throwable t) { t.printStackTrace(); } } } 不幸的是这个程序也无法执行完成它没有输出但却一直悬在那里这是为什么那 JDK文档中对此有如此的解释因为本地的系统对标准输入和输出所提供的缓冲池有效所以错误的对标准输出快速的写入和从标准输入快速的读入都有可能造成子进程的锁甚至死锁。 文档引述完了作者又开始批评了他说JDK仅仅说明为什么问题会发生却并没有说明这个问题怎么解决这的确是个问题哈。紧接着作者 说出自己的做法就是在执行完外部命令后我们要控制好Process的所有输入和输出视情况而定在这个例子里边因为调用的是Javac而他在没有 参数的情况下会将提示信息输出到标准出错所以在下面的程序中我们要对此进行处理。 import java.util.*; import java.io.*; public class MediocreExecJavac { public static void main(String args[]) { try { Runtime rt Runtime.getRuntime(); Process proc rt.exec(javac); InputStream stderr proc.getErrorStream(); InputStreamReader isr new InputStreamReader(stderr); BufferedReader br new BufferedReader(isr); String line null; System.out.println(); while ( (line br.readLine()) ! null) System.out.println(line); System.out.println(); int exitVal proc.waitFor(); System.out.println(Process exitValue: exitVal); } catch (Throwable t) { t.printStackTrace(); } } } 程序的运行结果为 E:classescomjavaworldjpitfallsarticle2java MediocreExecJavac Usage: javac where includes: -g Generate all debugging info -g:none Generate no debugging info -g:{lines,vars,source} Generate only some debugging info -O Optimize; may hinder debugging or enlarge class files -nowarn Generate no warnings -verbose Output messages about what the compiler is doing -deprecation Output source locations where deprecated APIs are used -classpath Specify where to find user class files -sourcepath Specify where to find input source files -bootclasspath Override location of bootstrap class files -extdirs Override location of installed extensions -d Specify where to place generated class files -encoding Specify character encoding used by source files -target Generate class files for specific VM version Process exitValue: 2 哎不管怎么说还是出来了结果作者作了一下总结就是说为了处理好外部命令大量输出的情况你要确保你的程序处理好外部命令所需要的输入或者输出。 下一个题目当我们调用一个我们认为是可执行程序的时候容易发生的错误今天晚上我刚刚犯这个错误没事做这个练习时候发生的 import java.util.*; import java.io.*; public class BadExecWinDir { public static void main(String args[]) { try { Runtime rt Runtime.getRuntime(); Process proc rt.exec(dir); InputStream stdin proc.getInputStream(); InputStreamReader isr new InputStreamReader(stdin); BufferedReader br new BufferedReader(isr); String line null; System.out.println(); while ( (line br.readLine()) ! null) System.out.println(line); System.out.println(); int exitVal proc.waitFor(); System.out.println(Process exitValue: exitVal); } catch (Throwable t) { t.printStackTrace(); } } } A run of BadExecWinDir produces: E:classescomjavaworldjpitfallsarticle2java BadExecWinDir java.io.IOException: CreateProcess: dir error2 at java.lang.Win32Process.create(Native Method) at java.lang.Win32Process.(Unknown Source) at java.lang.Runtime.execInternal(Native Method) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at BadExecWinDir.main(BadExecWinDir.java:12) 说实在的这个错误还真是让我摸不着头脑我觉得在windows中返回2应该是没有找到这个文件的缘故可能windows 2000中只有cmd命令dir命令不是当前环境变量能够解释的吧。我也不知道了慢慢往下看吧。 嘿果然和作者想的一样就是因为dir命令是由windows中的解释器解释的直接执行dir时无法找到dir.exe这个命令所以会出 现文件未找到这个2的错误。如果我们要执行这样的命令就要先根据操作系统的不同执行不同的解释程序command.com 或者cmd.exe。 作者对上边的程序进行了修改 import java.util.*; import java.io.*; class StreamGobbler extends Thread { InputStream is; String type; StreamGobbler(InputStream is, String type) { this.is is; this.type type; } public void run() { try { InputStreamReader isr new InputStreamReader(is); BufferedReader br new BufferedReader(isr); String linenull; while ( (line br.readLine()) ! null) System.out.println(type line); } catch (IOException ioe) { ioe.printStackTrace(); } } } public class GoodWindowsExec { public static void main(String args[]) { if (args.length 1) { System.out.println(USAGE: java GoodWindowsExec ); System.exit(1); } try { String osName System.getProperty(os.name ); String[] cmd new String[3]; if( osName.equals( Windows NT ) ) { cmd[0] cmd.exe ; cmd[1] /C ; cmd[2] args[0]; } else if( osName.equals( Windows 95 ) ) { cmd[0] command.com ; cmd[1] /C ; cmd[2] args[0]; } Runtime rt Runtime.getRuntime(); System.out.println(Execing cmd[0] cmd[1] cmd[2]); Process proc rt.exec(cmd); // any error message? StreamGobbler errorGobbler new StreamGobbler(proc.getErrorStream(), ERROR); // any output? StreamGobbler outputGobbler new StreamGobbler(proc.getInputStream(), OUTPUT); // kick them off errorGobbler.start(); outputGobbler.start(); // any error??? int exitVal proc.waitFor(); System.out.println(ExitValue: exitVal); } catch (Throwable t) { t.printStackTrace(); } } } Running GoodWindowsExec with the dir command generates: E:classescomjavaworldjpitfallsarticle2java GoodWindowsExec dir *.java Execing cmd.exe /C dir *.java OUTPUT Volume in drive E has no label. OUTPUT Volume Serial Number is 5C5F-0CC9 OUTPUT OUTPUT Directory of E:classescomjavaworldjpitfallsarticle2 OUTPUT OUTPUT10/23/00 09:01p 805 BadExecBrowser.java OUTPUT10/22/00 09:35a 770 BadExecBrowser1.java OUTPUT10/24/00 08:45p 488 BadExecJavac.java OUTPUT10/24/00 08:46p 519 BadExecJavac2.java OUTPUT10/24/00 09:13p 930 BadExecWinDir.java OUTPUT10/22/00 09:21a 2,282 BadURLPost.java OUTPUT10/22/00 09:20a 2,273 BadURLPost1.java ... (some output omitted for brevity) OUTPUT10/12/00 09:29p 151 SuperFrame.java OUTPUT10/24/00 09:23p 1,814 TestExec.java OUTPUT10/09/00 05:47p 23,543 TestStringReplace.java OUTPUT10/12/00 08:55p 228 TopLevel.java OUTPUT 22 File(s) 46,661 bytes OUTPUT 19,678,420,992 bytes free ExitValue: 0 这里作者教了一个windows中很有用的方法呵呵至少我是不知道的就是cmd.exe /C 一个windows中注册了后缀的文档名windows会自动地调用相关的程序来打开这个文档我试了一下的确很好用但是好像文件路径中有空格的 话就有点问题我加上引号也无法解决。 这里作者强调了一下不要假设你执行的程序是可执行的程序要清楚自己的程序是单独可执行的还是被解释的本章的结束作者会介绍一个命令行工具来帮助我们分析。 这里还有一点就是得到process的输出的方式是getInputStream这是因为我们要从Java 程序的角度来看外部程序的输出对于Java来说就是输入反之亦然。 最后的一个漏洞的地方就是错误的认为exec方法会接受所有你在命令行或者Shell中输入并接受的字符串。这些错误主要出现在命令作 为参数的情况下程序员错误的将所有命令行中可以输入的参数命令加入到exec中这段翻译的不好凑合看吧。下面的例子中就是一个程序员想重定向一个 命令的输出。 import java.util.*; import java.io.*; // StreamGobbler omitted for brevity public class BadWinRedirect { public static void main(String args[]) { try { Runtime rt Runtime.getRuntime(); Process proc rt.exec(java jecho Hello World test.txt); // any error message? StreamGobbler errorGobbler new StreamGobbler(proc.getErrorStream(), ERROR); // any output? StreamGobbler outputGobbler new StreamGobbler(proc.getInputStream(), OUTPUT); // kick them off errorGobbler.start(); outputGobbler.start(); // any error??? int exitVal proc.waitFor(); System.out.println(ExitValue: exitVal); } catch (Throwable t) { t.printStackTrace(); } } } Running BadWinRedirect produces: E:classescomjavaworldjpitfallsarticle2java BadWinRedirect OUTPUTHello World test.txt ExitValue: 0 程序员的本意是将Hello World这个输入重订向到一个文本文件中但是这个文件并没有生成jecho仅仅是将命令行中的参数输出到标准输出中用户觉得可以像dos中重定向 一样将输出重定向到一个文件中但这并不能实现用户错误的将exec认为是一个shell解释器但它并不是如果你想将一个程序的输出重定向到其他的 程序中你必须用程序来实现他。可用java.io中的包。 import java.util.*; import java.io.*; class StreamGobbler extends Thread { InputStream is; String type; OutputStream os; StreamGobbler(InputStream is, String type) { this(is, type, null); } StreamGobbler(InputStream is, String type, OutputStream redirect) { this.is is; this.type type; this.os redirect; } public void run() { try { PrintWriter pw null; if (os ! null) pw new PrintWriter(os); InputStreamReader isr new InputStreamReader(is); BufferedReader br new BufferedReader(isr); String linenull; while ( (line br.readLine()) ! null) { if (pw ! null) pw.println(line); System.out.println(type line); } if (pw ! null) pw.flush(); } catch (IOException ioe) { ioe.printStackTrace(); } } } public class GoodWinRedirect { public static void main(String args[]) { if (args.length 1) { System.out.println(USAGE java GoodWinRedirect ); System.exit(1); } try { FileOutputStream fos new FileOutputStream(args[0]); Runtime rt Runtime.getRuntime(); Process proc rt.exec(java jecho Hello World); // any error message? StreamGobbler errorGobbler new StreamGobbler(proc.getErrorStream(), ERROR); // any output? StreamGobbler outputGobbler new StreamGobbler(proc.getInputStream(), OUTPUT, fos); // kick them off errorGobbler.start(); outputGobbler.start(); // any error??? int exitVal proc.waitFor(); System.out.println(ExitValue: exitVal); fos.flush(); fos.close(); } catch (Throwable t) { t.printStackTrace(); } } } Running GoodWinRedirect produces: E:classescomjavaworldjpitfallsarticle2java GoodWinRedirect test.txt OUTPUTHello World ExitValue: 0 这里就不多说了看看就明白紧接着作者给出了一个监测命令的小程序 import java.util.*; import java.io.*; // class StreamGobbler omitted for brevity public class TestExec { public static void main(String args[]) { if (args.length 1) { System.out.println(USAGE: java TestExec cmd); System.exit(1); } try { String cmd args[0]; Runtime rt Runtime.getRuntime(); Process proc rt.exec(cmd); // any error message? StreamGobbler errorGobbler new StreamGobbler(proc.getErrorStream(), ERR); // any output? StreamGobbler outputGobbler new StreamGobbler(proc.getInputStream(), OUT); // kick them off errorGobbler.start(); outputGobbler.start(); // any error??? int exitVal proc.waitFor(); System.out.println(ExitValue: exitVal); } catch (Throwable t) { t.printStackTrace(); } } } 对这个程序进行运行: E:classescomjavaworldjpitfallsarticle2java TestExec e:javadocsindex.html java.io.IOException: CreateProcess: e:javadocsindex.html error193 at java.lang.Win32Process.create(Native Method) at java.lang.Win32Process.(Unknown Source) at java.lang.Runtime.execInternal(Native Method) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at TestExec.main(TestExec.java:45) 193在windows中是说这不是一个win32程序这说明路径中找不到这个网页的关联程序下面作者决定用一个绝对路径来试一下。 E:classescomjavaworldjpitfallsarticle2java TestExec e:program filesnetscapeprogramnetscape.exe e:javadocsindex.html ExitValue: 0 好用了这个我也试了一下用的是IE。 最后作者总结了几条规则防止我们在进行Runtime.exec()调用时出现错误。 在一个外部进程执行完之前你不能得到他的退出状态 在你的外部程序开始执行的时候你必须马上控制输入、输出、出错这些流。 你必须用 Runtime.exec() 去执行程序 你不能象命令行一样使用 Runtime.exec() 。 在nea需要动态来添加到RNC的路由可以利用Runtime.exec方法来实现 具体实现如下 其中的ip参数到时候可以是动态获取就可以了。 String[] cmds {cmd.exe,/c,route add 11.11.11.11 mask 255.255.255.255 11.11.11.1 metric 30 tree.txt}; try { Process ps Runtime.getRuntime().exec(cmds); System.out.print(loadStream (ps.getInputStream())); System.err.print(loadStream (ps.getErrorStream())); } catch(IOException ioe) { ioe.printStackTrace(); } // read an input-stream into a String static String loadStream(InputStream in) throws IOException { int ptr 0; in new BufferedInputStream(in); StringBuffer buffer new StringBuffer(); while( (ptr in.read()) ! -1 ) { buffer.append((char)ptr); } return buffer.toString(); } 其中的 tree.txt可以把执行这个指令的结果重新定向到一个文件里面比如执行dirtree等指令的时候。 如果要执行dos以外的指令需要指定执行工作目录 比如执行某个exe程序的话利用了Runtime的 exec ( String [] cmdarray, String [] envp, File dir)方法来实现。File是这个exe程序的目录。 String[] cmds {cmd.exe,/c,radmin.exe}; try { Process ps Runtime.getRuntime().exec(cmds,null,new File(C://Program Files//Radmin)); System.out.print(loadStream(ps.getInputStream())); System.err.print(loadStream(ps.getErrorStream())); } catch(IOException ioe) { ioe.printStackTrace(); }