所以我得到了一个使用固定线程池来执行某些代码的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(),然后我就会这样做。 d全部设定。只有这似乎并非如此。我的代码现在看起来像这样:
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,就像我根本没有打过电话一样。 DRAT!
我还尝试让线程在执行任务时调用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)
感谢。
编辑:我的问题基本上是通过接受的答案解决的,但为了完整起见,我想补充一点,我无法使用期货和get()
来解决我的具体案例。我的个人任务消耗了大量的RAM但持续时间不同,因此我必须使用Java: ExecutorService that blocks on submission after a certain queue size答案中概述的小阻塞队列。我基本上陷入了认为newFixedThreadPool()
中的默认值对我的情况有效的陷阱,而实际上他们没有,而Brian的回答帮助揭露了那些错误的假设。谢谢Brian!
答案 0 :(得分:1)
以下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行,每行代表“这是对错误的流”,最后在控制台上打印一行。
您显示的代码段是在System.setErr(oldErr);
块中调用finally
...您是否等待在try
块中完成所有任务?
如果没有,它会解释你在评论中所做的陈述“我会看到打印到System.err的片段和打印到我的日志文件的片段” ...这几乎就是你期待发生。 .submit()
是一个非阻塞调用,返回Future
;您正在运行任务时重置流。