在System.out.close()之后重新创建System.out以在CONSOLE中再次打印

时间:2015-12-09 06:48:00

标签: java console jvm system.out

我有一个桌面应用程序,当冻结几分钟时,有一个监视冻结的线程,它开始转储所有线程的堆栈跟踪(这是在本机调用中完成的,因此JVM_DumpAllStacks可以被调用)到临时文件中。然后在本机调用之后将临时文件读取为String,并将其用于登录应用程序自己的日志记录框架。

问题是,在完成所有这些过程后,我无法将System.out恢复为CONSOLE流。

以下代码更好地解释了这一点。

public String getAllStackTraces() {

System.out.println("This will be printed in CONSOLE");

// This is NECESSARY for the jvm to dump stack traces in specific file which we are going to set in System.setOut call.
System.out.close(); 

File tempFile = File.createTempFile("threadDump",null,new File(System.getProperty("user.home")));
System.setOut(new PrintStream(new BufferedOutputStream(new FileOuptputStream(tempFile))));

//This native call dumps stack traces all threads to tempFile
callNativeMethodToDumpAllThreadStackTraces(); 

String stackTraces = readFileAsString(tempFile);
//close the tempFile PrintStream so as the next PrintStream object to set as 'out' and to take effect in the native side as well
System.out.close(); 

//Now I want to start printing in the CONSOLE again. How to do it again ?
//The below line does not work as FileDescriptor.out becomes invalid (i.e FileDescriptor.out.fd, handle = -1) after we do System.out.close() where out is PrintStream of console.
//System.setOut(new PrintStream(new BufferedOutputStream(new FileOuptputStream(FileDescriptor.out))));

PrintStream standardConsoleOutputStream = magicallyGetTheOutputStream() // How ???????????
System.setOut(standardConsoleOutputStream);
System.out.println("This will be printed in CONSOLE !ONLY! if we are able to get the new PrintStream of Console again magically");
} 

现在,有没有办法让magicallyGetTheOutputStream的控制台再次在控制台中开始打印?

注意:应用程序在java 5和6中运行。

1 个答案:

答案 0 :(得分:2)

请考虑以下代码,了解如何在不关闭的情况下存储原始System.out 以便以后将其恢复到完全荣耀:

    //Store, don't close
    PrintStream storeForLater = System.out;
    //Reassign
    System.out(setToNew);
    ...
    //Close reassigned
    setToNew.close();
    //Reset to old
    System.setOut(storeForLater);

作为原生代码的替代方案,您可以调用ThreadMXBean。返回的ThreadInfo对象包含有关持有的锁和线程正在等待的锁的信息。

public static void dumpThreads(PrintStream out) {
    ThreadInfo[] threads = ManagementFactory.getThreadMXBean()
            .dumpAllThreads(true, true);
    for(final ThreadInfo info : threads) {
        out.println("Thread: " + info.getThreadId() 
         + "/" + info.getThreadName()
         + " in State " + info.getThreadState().name());
        if(info.getLockName() != null) {
            out.println("- Waiting on lock: " + info.getLockInfo().toString()
                     + " held by " + info.getLockOwnerId()+"/"+info.getLockOwnerName());
        }
        for(MonitorInfo mi :  info.getLockedMonitors()) {
            out.println(" Holds a lock on a " + mi.getClassName() + 
                    " from " + mi.getLockedStackFrame().getClassName()+"."+mi.getLockedStackFrame().getMethodName() 
                    + ": " + mi.getLockedStackFrame().getLineNumber());
        }
        for(StackTraceElement elm : info.getStackTrace()) {
            out.println("   at " + elm.getClassName() + "."
                    + elm.getMethodName() + ":"+elm.getLineNumber());
        }
        out.println();
    }
}