- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当我使用 System.out.println 打印日志消息时,我正在编写一个基本的服务器程序。我编写了一个基本的类文件,使用它来写入日志。如果我写以下内容:
System.out.println("Hello, world!");
System.out.println("Goodbye, world");
期望的输出是:
Log message - Hello, world!
Log message - Goodbye, world!
最终发生的情况与期望的输出不匹配。相反,它输出到以下内容。
Log message - Hello, world!
Goodbye, world!
主要方法的代码:
public static void main(String[] args){
LogManager.start();
System.out.println("Hello, world!");
System.out.println("Goodbye, world!");
LogManager.stop();
}
LogManager 类切换打印输出的默认 PrintStream
,并保留旧版本的副本以打印日志消息。但是,“Log message - ”并不总是带有前缀。不过,当每次 println
调用之间 hibernate 2000 毫秒时,输出如下所示。
Log message - Hello, world!
Log message - Goodbye, world!Log message -
LogManager的代码如下。
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
public class LogManager implements Runnable{
private final PrintStream ps;
private final OutputStream out;
private static boolean cont = true;
public static void start(){
OutputStream stdout = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(stdout);
Thread th = new Thread(new LogManager(System.out, stdout));
System.setOut(ps);
th.start();
}
public static void stop(){
cont = false;
}
public LogManager(PrintStream std, OutputStream out){
this.ps = std;
this.out = out;
}
@Override
public void run() {
ByteArrayOutputStream baos = (ByteArrayOutputStream) out;
while(true){
if(!cont) return;
byte[] bytes = baos.toByteArray();
if(bytes.length > 0){
baos.reset();
ps.print("Log message - " + new String(bytes));
}
}
}
}
有人可以指出我做错了什么吗,我们将不胜感激。我想远离库,因为我想将 JAR 大小保持在最小,不需要包含额外的包,尽管主要是因为我知道我没有使用任何其他人的库来实现我正在做的事情。
最佳答案
您有一些竞争条件。
首先,一旦 stop()
完成,您的程序就会结束。当发生这种情况时,LogManager 线程可能有机会看到已写入的新字节:
cont = false
cont == false
并在有机会写入其字节之前停止。此外,您还可以使用 baos.toByteArray()
,然后作为单独的操作执行 baos.reset()
。如果有人在两个操作之间写一些东西会发生什么?它们不会反射(reflect)在 bytes
变量中,但 reset()
会删除它们。
要解决第一个问题,您可以在返回之前进行最后一次检查。换句话说,如果您将整个 toByteArray()/reset()/println 位重构为方法 readAndPrint()
,则 return
语句将变为:
if (!cont) {
readAndPrint(); // one last read to empty the buffer
return;
}
要解决第二个问题,您应该在锁定 boas
的同时执行 toByteArray()
和 reset()
(这将还锁定对该流的写入,因为 ByteArrayOutputStream 中的所有读取和写入都是同步的)。这将确保在您执行这两个操作时没有其他人可以写入。
byte[] bytes;
synchronized (baos) {
bytes = baos.toByteArray();
baos.reset();
}
if (bytes.length > ) { ...
此外,您应该将 cont
字段设置为 volatile ,以便一个线程中的写入始终可以在另一个线程中看到。
请注意,上述内容仍会让您参加一些比赛。例如,如果您有两个“主”线程,您可以想象这样一种情况:其中一个线程调用 stop()
,而另一个线程仍在尝试打印消息。解决方案是以某种方式对其进行协调,以便在您调用 stop()
时,所有线程都已完成其日志记录。
多线程是一个非常复杂和微妙的主题,很难通过实验来学习。如果您还没有这样做,我强烈建议您阅读一本书或深入的教程,以充分掌握问题和解决问题的方法。
最后,您没有询问输出中的奇怪换行符,但它们可能是由于您使用正在刷新的 PrintStream(从而将其内容写入 BAOS)作为信号用于打印前缀,而不是在字节缓冲区中看到换行符。如果刷新发生在写入换行符之前,您将看到所看到的行为。
关于Java PrintStream 重定向行为异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45124527/
PrintStream的printf方法的返回类型是PrintStream,每次调用它都会返回这个对象(其他打印方法都是void)。那么为什么要这样设计呢?就此而言,如果您有一个任何类型的对象,并且该
我正在运行一个由另一个人编写的 Java 程序,其数据量超过了该程序最初设计的数据量,例如输入文件长 10 倍,大致为二次运行时间。我遇到了不同的问题,现在的目标是一点一点地解决它们。 在执行期间,当
我在本地主机的端口打开一个服务器套接字,例如11111,并且我还包括流数据的打印流,我希望像这样整齐地输出它 PrintStream ps=new PrintStream(socket.getOutp
我使用的是 eclipse IDE,有时,根据代码的不同,System.err 输出会先于 System.out 打印。例如: public static void main(String[]
import java.io.PrintStream; import java.util.Scanner; public class OutputTest { public static vo
in = new BufferedReader (new InputStreamReader(client.getInputStream())); out = new DataOutputStream
当我使用 System.out.println 打印日志消息时,我正在编写一个基本的服务器程序。我编写了一个基本的类文件,使用它来写入日志。如果我写以下内容: System.out.println("
这个问题在这里已经有了答案: File Write - PrintStream append (2 个答案) 关闭 6 年前。 我想使用 PrintStream 将测试结果写入已创建的文本文件。可惜
我正在查看一个类,该类通过其构造函数获取一个 OutputStream 对象,并使用它创建一个 PrintStream 对象,如下所示: this.pout = new PrintStream(out
我不明白为什么我的代码导致 PrintStream 转到新行: // displays the total time of the leak in months from the calculateL
我正在制作一个服务器客户端系统,其中客户端将向服务器写入一条消息,服务器将其保存为字符串并将其打印在控制台中。但是,当系统尝试读取该行时,我会在控制台中收到“PrintStream 错误”。没有错误或
我在第 58 行收到错误,表示未找到该文件,但 PrintStream 不应该创建该文件吗? (注意:根本没有创建任何文件。) 谢谢! 为什么需要添加更多详细信息我已经说了什么我需要说 import
程序按预期在我的控制台上输出,但它现在只能创建空白输出文件。我不知道出了什么问题。这是我认为是我的麻烦根源的方法: public static PrintStream getOutputPri
我正在运行一些不安全的代码,我已将其 stdout 和 stderr 流设置为包装在 PrintStream< 中的 FileStream/s。 (标准输出/错误必须重定向。) 是否有任何方法可以配置
请看一下我的代码。 import java.util.*; import java.io.*; public class LibraryDriver { public static void
我有一个用 Java 编写的 GUI 程序,它使用 System.out.println 将数据输出到命令行。数据旨在通过管道输送到另一个程序中。作为示例,我将通过 head 传输程序: $ java
这个问题已经有答案了: System.out to a file in java (7 个回答) Redirect System.out.println (6 个回答) 已关闭 3 年前。 怎么会Sy
Java 文档 page System 类表示其字段之一称为“out”: 静态打印流输出 如果我然后查看文档 page对于 PrintStream 类,它表示其继承字段之一称为“out”。如果我然后单
我想使用 PrintWriter 或 PrintStream 将格式化字符串写入输出流(我无法控制其创建)。然而,刷新底层 OutputStream 会对性能造成很大影响。 是否需要刷新 PrintW
最新 SSCCEE 为什么下面的示例输出不同的字符串? package tests.java; import java.io.IOException; import java.io.OutputStr
我是一名优秀的程序员,十分优秀!