我正在编写一个多线程Java程序,其中每个线程可能需要将其标准输出重定向到一个单独的文件。每个线程都有自己的文件。是否有可能在“每个线程”的基础上重定向System.out,还是所有线程对System.out全局更改?
你是对的,但不是你想的那样。当一个线程使用
System.out.println();
它获取引用System.out
的副本,但不获取此引用的对象的副本。
这意味着所有线程通常会看到同一个对象来写入输出。
注意:如果调用系统,则此字段将处于非线程安全状态。setOut(PrintStream)
如果使用此选项,则可能会出现一种不希望出现的争用情况,即不同的线程需要具有不同的系统本地副本。出来这不能用来解决这个问题。
是否可以重定向系统。以“每线程”为基础
您可以通过更换系统来实现这一点。使用自己的特定于线程的实现。i、 e.PrintStream的一个子类。我这样做是为了记录,我希望每个线程的输出是一致的,而不是交错的。e、 g.想象一下同时在两个线程中打印两个堆栈轨迹
是否可以重定向系统。以“每线程”为基础
Maia公司的一些开发人员提供了一个PrintStream的公共实现,在本文中,它为每个线程提供了一个“STDOUT”:“特定于线程的System.out”。
在它们的实现中,它们只覆盖write方法、flush、close和checkError。对他们来说,这似乎足够了。
他们不需要像@Gray在回答中所说的那样“覆盖所有调用的方法,以使每个线程都能工作”。
NOTA:
请在下面找到Maia的原始代码。
我在wayback机器上找到了它。原始页面已从Maia的网站上删除。我在这里复制它是为了读者的好奇心。我不提供对这段代码的任何支持。
Main.java
创建ThreadPrintStream,并将其作为系统安装。然后创建并启动10个线程。
public class Main {
public static void main(String[] args) {
// Call replaceSystemOut which replaces the
// normal System.out with a ThreadPrintStream.
ThreadPrintStream.replaceSystemOut();
// Create and start 10 different threads. Each thread
// will create its own PrintStream and install it into
// the ThreadPrintStream and then write three messages
// to System.out.
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new StreamText());
thread.start();
// Report to the console that a new thread was started.
System.out.println("Created and started " + thread.getName());
}
}
}
流文本。JAVA
一个简单的Runnable for each thread,为线程的输出打开一个文件,并将其安装到ThreadPrintStream中。
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
/** A small test class that sets System.out for the currently executing
* thread to a text file and writes three messages to System.out. */
public class StreamText implements Runnable {
@Override
public void run() {
try {
// Create a text file where System.out.println()
// will send its data for this thread.
String name = Thread.currentThread().getName();
FileOutputStream fos = new FileOutputStream(name + ".txt");
// Create a PrintStream that will write to the new file.
PrintStream stream = new PrintStream(new BufferedOutputStream(fos));
// Install the PrintStream to be used as System.out for this thread.
((ThreadPrintStream)System.out).setThreadOut(stream);
// Output three messages to System.out.
System.out.println(name + ": first message");
System.out.println("This is the second message from " + name);
System.out.println(name + ": 3rd message");
// Close System.out for this thread which will
// flush and close this thread's text file.
System.out.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
ThreadPrintStream.java
扩展了java。伊奥。打印流。ThreadPrintStream的一个对象替换了正常的系统。开发并维护一个单独的java。伊奥。每个线程的打印流。
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
/** A ThreadPrintStream replaces the normal System.out and ensures
* that output to System.out goes to a different PrintStream for
* each thread. It does this by using ThreadLocal to maintain a
* PrintStream for each thread. */
public class ThreadPrintStream extends PrintStream {
/** Changes System.out to a ThreadPrintStream which will
* send output to a separate file for each thread. */
public static void replaceSystemOut() {
// Save the existing System.out
PrintStream console = System.out;
// Create a ThreadPrintStream and install it as System.out
ThreadPrintStream threadOut = new ThreadPrintStream();
System.setOut(threadOut);
// Use the original System.out as the current thread's System.out
threadOut.setThreadOut(console);
}
/** Thread specific storage to hold a PrintStream for each thread */
private ThreadLocal<PrintStream> out;
private ThreadPrintStream() {
super(new ByteArrayOutputStream(0));
out = new ThreadLocal<PrintStream>();
}
/** Sets the PrintStream for the currently executing thread. */
public void setThreadOut(PrintStream out) {
this.out.set(out);
}
/** Returns the PrintStream for the currently executing thread. */
public PrintStream getThreadOut() {
return this.out.get();
}
@Override public boolean checkError() {
return getThreadOut().checkError();
}
@Override public void write(byte[] buf, int off, int len) {
getThreadOut().write(buf, off, len);
}
@Override public void write(int b) { getThreadOut().write(b); }
@Override public void flush() { getThreadOut().flush(); }
@Override public void close() { getThreadOut().close(); }
}
是否可以重定向系统。以“每线程”为基础
不,这是不可能的。System.out
是静态的,当JVM最初引导时,每个JVM都有一个作为系统类加载器的一部分加载。虽然当然建议每个线程使用适当的日志调用,但我认为有一些原因使您不能这样做。可能是第三方库或其他代码以这种方式使用System.out
。
你可以做的一件事(作为一个激进的建议)是制作你自己的PrintStream
,它委托给一个线程本地
最后,如果您因为担心并发而问这个问题,那么
System.out
是一个PrintStream
,因此它已经被同步了,并且可以被多个线程安全地使用。
问题内容: 我正在编写一个多线程Java程序,其中每个线程可能都需要将其标准输出重定向到一个单独的文件。每个线程都有其自己的文件。是否可以在“每个线程”的基础上重定向System.out或在所有线程上全局更改System.out? 问题答案: 是否可以基于“每线程”重定向System.out 不,这是不可能的。 是静态的,并且在JVM最初启动时,每个JVM都会作为系统类加载器的一部分进行加载。尽管
我试图理解这句话的含义: 每个Java虚拟机线程都有自己的pc(程序计数器)寄存器。在任何时候,每个Java虚拟机线程都在执行单个方法的代码,即该线程的当前方法(§2.6)。 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.1 我假设JVM线程像任何其他线程一样工作——每次调度线程运行(比如Linux内
我在试着理解这句话的意思: 每个Java虚拟机线程都有自己的pc(程序计数器)寄存器。在任何一点上,每个Java虚拟机线程都在执行单个方法的代码,即该线程的当前方法(§2.6)。 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.1 我假设JVM线程的工作方式与任何其他线程一样--每次调度线程运行时(比方
我有多个带有注释的组件,我看到Spring一次只启动一个组件,即使它们被安排在同一时间运行。
我正在尝试设置一个Java程序,其中每个线程都可以使用自己的代理。 现在我只找到了一种全局设置代理的方法。(http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html) 如前所述,这些设置会影响使用这些选项调用的VM的整个生命周期内的所有http连接。然而,使用该系统是可能的。setProperty()方法,使其具有
当我运行一个多线程的java程序时,在执行ps -eF | grep program-name时,我只看到一个进程。作为该进程的一部分运行的线程是子进程。在调度方面,操作系统对待单线程和多线程进程是否有所不同?