Java中多个线程使用System.out.println

6
我是一名有用的助手,能够将文本进行翻译。
我有一个多线程的Java应用程序,为了调试目的,它会将接收到的消息信息输出到控制台。每当应用程序接收到一条消息时,它会在该消息上调用 System.out.println(String)
但问题在于,如果应用程序被大量的消息淹没,System.out.println() 将打印错误的信息(例如旧的缓冲区信息)。这让我开始思考是否存在线程问题,即多个线程同时调用 println 函数,而没有正确地刷新缓冲区。
在我的主程序(线程)中,我有如下代码:
while(iterator.hasNext())
{
    SelectionKey key = iterator.next();

    channel.receive(buffer);     // The buffer is a ByteBuffer.
    buffer.flip();

    new Thread(new ThreadToPrintTheMessage(buffer)).start();

    buffer.clear();

    iterator.remove();
}

在我的线程中,我有类似以下内容的语句:

@Override
public void run()
{
    System.out.println(message);
    System.out.flush();   // I have better results with this.  But, it doesn't
                          // fully resolve the issue.
}

有没有简单的方法让我多线程打印到控制台,而不包含旧信息缓存?
谢谢。
编辑:已更新主线程中的代码,以更好地代表我的程序在做什么。

2
你能展示一些“旧缓冲区信息”吗?System.out.println是同步的,所以你不应该得到“旧”的信息。 - Gray
多个线程同时在控制台上打印?你的意思是每次一个线程吗? - kosa
1
@Phanto:看起来你有两个线程在某个地方写入同一个变量/字段,它们正在互相覆盖。 - Sam Goldberg
2
@Phanto:看起来你正在将缓冲对象与多个线程共享。 这是行不通的。 每个线程需要自己单独的缓冲区对象,或者主线程需要将缓冲区转换为本地字符串变量,然后将字符串传递给线程。 - Sam Goldberg
1
@Phanto:所以,你正在尝试异步处理一个在异步调用完成后立即清除(甚至写入)的缓冲区?那是行不通的,你应该将buffer的副本传递给ThreadToPrintTheMessage()构造函数(除非你在构造函数内部自己复制)。 - Alexander Pavlov
显示剩余7条评论
4个回答

3
synchronized (System.out) {
    System.out.println(message);
    System.out.flush();
}

@Gray,我只是认为这可能是println()flush()之间的竞争,但显然不是这种情况。@Phanto,你得到了什么样的输出? - Alexander Pavlov
@AlexanderPavlov,请查看主帖中的评论。 - Phanto
@AlexanderPavlov 如果您不使用同步块,则在println()和flush()之间可能会存在竞争条件,如果是这样,为什么/如何?如果不是,那么为什么/如何? - Asif Mushtaq
可以的。为什么不呢? - Alexander Pavlov

2

你能提供一个小例子吗? - Phanto

2
这里可能会有一些修复问题的示例代码:
while(iterator.hasNext())
{
    SelectionKey key = iterator.next();

    channel.receive(buffer);     // The buffer is a ByteBuffer.
    buffer.flip();
    byte[] bytes = new byte[buffer.limit()];  // copy buffer contents to an array
    buffer.get(bytes);
    // thread will convert byte array to String
    new Thread(new ThreadToPrintTheMessage(bytes)).start();

    buffer.clear();

    iterator.remove();
}

这就做到了!你和Alexander Pavlov找出了问题所在...我试图打印一个被不同资源共享和修改的缓冲区。 - Phanto

2

我没有时间检查println的源代码以确保它始终是线程安全的(如果您愿意,您可以检查),但您确定您的println有问题吗?可能代码运行的时间与您想象的不同。线程经常被锁定或者被调度程序忘记,所以您认为应该运行 A、B、C、D 的代码可能会运行 B、C、D、A。然后您就会想,为什么println出现了问题,会打印您认为最先运行的内容。这只是一个非常简单的例子。多线程下您期望发生的事情和实际上发生的事情之间的差异可能会让您大吃一惊。通常,线程与核心的比率越高,问题就越严重。单核机器总是做与您期望相反的事情。

即使没有多个线程,您仍然可能遇到这个问题。我的第一次震惊来自事件队列(Windows 3.1上),它们并不认同我对内容运行的时间观点。我花了一段时间才弄明白消息被打乱了,因为操作系统对它们的运行方式与我的想法大不相同。

可能System.out.println和flush之间有一些我不知道的微妙之处,但即使您解决了所有这些问题,请注意那些线程有自己独立的思考方式。即使使用Logger也不能解决所有问题。


1
根据多个人的说法,println是线程安全的,因此它确实可能会被打乱时间表。 - malexmave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接