gpt4 book ai didi

java - 多线程的 System.setErr() 的正确方法?

转载 作者:太空宇宙 更新时间:2023-11-04 07:09:54 25 4
gpt4 key购买 nike

所以我有一个使用固定线程池来执行一些代码的 Java 应用程序。此代码包括使用输出到 System.err 的第三方库。当我以单线程方式执行这段代码时,我将 System.err“重定向”到 PrintStream,最终打印到 log4j 日志。基本上它看起来像这样:

 PrintStream oldErr = System.err;
System.setErr(new PrintStream(/* custom logging stream here */));

try
{
// do computationally expensive task here
}
finally
{
System.setErr(oldErr);
}

这按预期工作了。输出打印到日志文件而不是控制台,我可以通过更改 log4j 配置来完全删除输出。完美。

当我开始添加多线程时,我做了一些研究并遇到了这个问题:In a multithreaded Java program, does each thread have its own copy of System.out? ,这意味着我应该在启动线程池之前执行一次 System.setErr() ,然后就一切就绪了。只是情况似乎并非如此。我的代码现在看起来像这样:

 PrintStream oldErr = System.err;
System.setErr(new PrintStream(/* custom logging stream here */));

ExecutorService threadPool = Executors.newFixedThreadPool(maxThreadCount);

try
{
// shove computationally expensive task off to a thread
// using threadPool.execute()
}
finally
{
System.setErr(oldErr);
}

但是,在启动线程池之前调用 System.setErr() 效果为零。所有线程都将其输出打印到 System.err,就好像我根本没有进行调用一样。该死!

我还尝试让线程在执行任务时调用 System.setErr(),但是存在一些明显的竞争条件问题——控制台输出间歇性,并且总体感觉很脏。在一次测试中,它们甚至看起来陷入了僵局。

我错过了一些简单的事情吗? FWIW,这是我的 JVM 详细信息:

java version "1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b07)
Java HotSpot(TM) 64-Bit Server VM (build 17.0-b17, mixed mode)

谢谢。

编辑:我的问题基本上是通过接受的答案解决的,但为了完整起见,我想补充一点,我无法使用 Futures 和 get() 解决我的特定情况。我的各个任务消耗大量 RAM,但持续时间各不相同,因此我必须使用一个小的阻塞队列,如 Java: ExecutorService that blocks on submission after a certain queue size 的答案中所述。 。我基本上陷入了这样的陷阱:认为 newFixedThreadPool() 中的默认值适用于我的情况,而实际上它们并不适用,而 Brian 的回答帮助揭露了这些错误的假设。谢谢布莱恩!

最佳答案

以下 SSCCE 完全符合您的要求:

public class App
{
public static void main(String[] args) throws FileNotFoundException, InterruptedException, ExecutionException
{
PrintStream oldErr = System.err;
System.setErr(new PrintStream(new File("test")));

ExecutorService threadPool = Executors.newFixedThreadPool(5);
List<Future<?>> fList = new LinkedList<Future<?>>();
for (int i = 0; i < 5; i++)
{
fList.add(threadPool.submit(new Runnable() {

@Override
public void run()
{
System.err.println("This is to the err stream");
}

}));
}

for (Future<?> f : fList)
{
f.get();
}

threadPool.shutdown();

System.setErr(oldErr);
System.err.println("This is to the err stream");
}
}

运行此示例后,文件“test”包含 5 行,每行都表示“这是到 err 流的”,最后一行附加打印到控制台。

您显示的代码片段正在 finally block 中调用 System.setErr(oldErr); ...您是否已等待该 try block 中的所有任务完成?

如果不是,它会解释您在注释中所做的声明:“我会看到输出片段打印到 System.err 并将片段打印到我的日志文件” ...这几乎就是您期望发生的情况。 .submit() 是一个非阻塞调用,返回一个 Future;您在任务运行时重置流。

关于java - 多线程的 System.setErr() 的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20809502/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com