首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于System.out的同步

基于System.out的同步
EN

Stack Overflow用户
提问于 2014-06-02 14:14:05
回答 4查看 1.7K关注 0票数 6

通过调用System.outSystem.setErr,我将System.setOut更改为打印为文件。

每天午夜,我们都要重命名(归档)当前日志文件,并创建一个新的日志文件。

代码语言:javascript
复制
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()

代码语言:javascript
复制
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的调用来实现这个原子呢?我在考虑尝试

代码语言:javascript
复制
synchronized (System.out) {

}

但我不确定这里的内在锁能起什么作用。特别是因为我在操作期间取消了out对象。

有人知道我如何确保这里的适当同步吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-06-02 14:26:54

是的,您可以通过这种方式实现适当的同步。这是一个样本测试。

代码语言:javascript
复制
@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);
}

产出如下:

代码语言:javascript
复制
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
票数 4
EN

Stack Overflow用户

发布于 2014-06-02 14:21:34

在关闭旧的之前,我会创造出新的:

代码语言:javascript
复制
PrintStream old = System.out;
out = new FileOutputStream(outputfilename, true);
System.setOut(new PrintStream(out));
old.close();

这样,在创建和分配新PrintStream之前,旧的才会关闭。在任何时候,PrintStream中都有一个有效的System.out。

不需要synchronized块,因为所有东西都在同一个线程中。

票数 5
EN

Stack Overflow用户

发布于 2014-06-02 14:37:12

由于您无法控制调用代码对System.out所做的操作,因此无法安全地完成此任务。想想看:

代码语言:javascript
复制
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)。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23996666

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档