通过调用System.out和System.setErr,我将System.setOut更改为打印为文件。
每天午夜,我们都要重命名(归档)当前日志文件,并创建一个新的日志文件。
if (out != null) {
out.close();
out = null;
File f = new File(outputfilename);
f.renameTo(new File(dir.getPath().replace(".log", "-" + System.currentTimeMillis() + ".log")))
StartLogFile();
}The StartLogFile()
if (out == null) {
out = new FileOutputStream(outputfilename, true);
System.setOut(new PrintStream(out));
System.setErr(new PrintStream(out));
}我把异常处理留出来了。
我担心的是,如果有东西试图在out.close()和setOut/setErr之间打印,那么我就会错过一个日志。
我真正的问题是,如何通过其他对System.out.println的调用来实现这个原子呢?我在考虑尝试
synchronized (System.out) {
}但我不确定这里的内在锁能起什么作用。特别是因为我在操作期间取消了out对象。
有人知道我如何确保这里的适当同步吗?
发布于 2014-06-02 14:26:54
是的,您可以通过这种方式实现适当的同步。这是一个样本测试。
@Test
public void test() throws InterruptedException {
new Thread(()->{
while(true){
System.out.println("printing something");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}).start();
Thread.sleep(500);
synchronized (System.out){
System.out.println("changin system out");
Thread.sleep(2000);
System.out.println("finished with sysout");
}
Thread.sleep(2000);
}产出如下:
printing something
printing something
printing something
printing something
printing something
changin system out
finished with sysout
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something发布于 2014-06-02 14:21:34
在关闭旧的之前,我会创造出新的:
PrintStream old = System.out;
out = new FileOutputStream(outputfilename, true);
System.setOut(new PrintStream(out));
old.close();这样,在创建和分配新PrintStream之前,旧的才会关闭。在任何时候,PrintStream中都有一个有效的System.out。
不需要synchronized块,因为所有东西都在同一个线程中。
发布于 2014-06-02 14:37:12
由于您无法控制调用代码对System.out所做的操作,因此无法安全地完成此任务。想想看:
public void doSomethingTakingALongTime(PrintStream target) {
// lots of code
}
// somewhere else
doSomethingTakingALongTime(System.out);您永远无法确定局部变量或方法参数中的某个地方没有System.out引用的副本。
解决这一问题的正确方法是在程序开始时只设置一次System.out,而不是使用标准PrintStream,而是使用您自己的实现将所有内容委托给当前目标。
然后,您将完全控制通过System.out完成的每一个输出,并可以在需要时在空闲时同步。如果您自己的实现同步了每个操作,那么甚至不会出现更改日志目标时会发生什么的问题--其他每个调用方都会被同步锁阻塞。
顺便说一句。使用System.out进行日志记录是有问题的。事实上,日志记录的标准是使用log4j。考虑切换到那个。
编辑:实际上,实现这个委托是相当容易的。有一个构造函数PrintStream(OutputStream)。这意味着您只需在OutputStream中实现委托(它的方法比PrintStream少得多),并将System.out设置为新的PrintStream(YourRetargettingOutputStream)。
https://stackoverflow.com/questions/23996666
复制相似问题