- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
所以我有一个使用固定线程池来执行一些代码的 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/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!