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

时间:2012-02-27 15:39:49

标签: java multithreading buffer println

我有一个多线程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.
}

我是否有一种简单的方法让多个线程一次打印到控制台而不包含包含旧信息的缓冲区?

由于

编辑:更新主线程中的代码,以更好地代表我的程序正在做什么。

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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();
}

答案 2 :(得分:2)

我没有时间检查println来源,确保它的线程安全(如果你愿意,你可以),但是你确定你的println错了吗?很可能代码运行的时间与您想象的完全不同。线程经常挂在锁上或者只是被调度程序忘记了,所以你认为应该运行A,B,C,D可以运行B,C,D,A。然后你想知道为什么println搞砸了,打印到底是什么你认为先跑了。这是一个非常简单的例子。您希望多线程发生的事情与发生的事情之间的差异可能真的令人震惊。通常,线程与核心比率越高,它就越差。单核机器总能做到与您期望的完全相反的一切。

你甚至不需要多个线程来解决这个问题。我的第一个颠簸来自事件队列(在Windows 3.1上),它没有分享我对什么时候应该运行的看法。我花了一段时间才弄明白这些消息是混乱的,因为操作系统对它们应该如何运行有着截然不同的想法。

System.out.println和flush可能会有一些细微之处我不知道,但即使你完成了所有工作,也要注意那些线程与他们自己的思想相反。即便记录器也无法解决您的所有问题。

答案 3 :(得分:1)

您应该使用Java.util.logging或其他一些日志框架来实现此目的。

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/logging/Logger.html

import java.util.logging.Logger;
....
Logger log = Logger.getLogger("com.something.something");
....
log.log(Level.Info, "Message");