java - ArrayList 的多线程打印

标签 java multithreading logging thread-safety threadpool

我试图让记录器将所有日志消息从应用程序打印到控制台,并在将来打印到外部文件。当我触发函数“dumpToConsole”时,它应该执行此操作。应该通过 3 个线程以多线程方式完成,所有 3 个线程都访问 CopyOnWriteArrayList。问题在于输出不按顺序排列,是应有顺序的三倍。我得到的不是 3 条消息,而是 9 条消息。例如,我需要 3 个线程来打印所有单独的打印 1,而不是每个线程打印 3。

请参阅下文,了解我对此的实际实现。

我的主题:

public class LoggingThread extends Thread {
private boolean isStopped = false;
private CopyOnWriteArrayList<LogMessage> messages;

public LoggingThread(CopyOnWriteArrayList messages) {
    this.messages = messages;
}

@Override
public void run() {
    for (int i = 0; i < messages.size(); i++) {
        writeMessageToConsole(messages.get(i).getMessageText(), messages.get(i).getLogLevel());
    }
}

private synchronized void writeMessageToConsole(String message, LogLevel logLevel) {
    System.out.println(message + " (" + logLevel + ")");
}
}

我的记录器:

public class Logger implements ILogger {
private static ILogger instance = null;
private CopyOnWriteArrayList<LogMessage> messages = new CopyOnWriteArrayList<LogMessage>();
private LoggingThread thread1;
private LoggingThread thread2;
private LoggingThread thread3;

public static ILogger getInstance() {
    if (instance == null) {
        instance = new Logger();
    }

    return instance;
}

public CopyOnWriteArrayList<LogMessage> getMessages() {
    return messages;
}

public void log(Exception ex) {
    log(ex.getMessage(), LogLevel.FATAL);
}

public void log(String message, LogLevel logLevel) {
    messages.add(new LogMessage(message, logLevel));
}

public LogMessage getLastLog() {
    if(!messages.isEmpty()) {
        return messages.get(messages.size() -1);
    }

    else {
        return new LogMessage("", LogLevel.DEBUG);
    }
}

public void dumpToConsole() {
    log("TEST1", LogLevel.FATAL);
    log("TEST2", LogLevel.DEBUG);
    log("TEST3", LogLevel.FATAL);

    thread1 = new LoggingThread(this.messages);
    thread2 = new LoggingThread(this.messages);
    thread3 = new LoggingThread(this.messages);

    thread1.start();
    thread2.start();
    thread3.start();

    try {
        thread1.join();
        thread2.join();
        thread3.join();
    }

    catch (InterruptedException e) {
        log(e.getMessage(), LogLevel.FATAL);
    }

    thread1.interrupt();
    thread2.interrupt();
    thread3.interrupt();
}
}

还有我的消息类:

public class LogMessage {
private String messageText;
private LogLevel logLevel;

public LogMessage(String messageText, LogLevel logLevel) {
    this.messageText = messageText;
    this.logLevel = logLevel;
}

public LogLevel getLogLevel() {
    return logLevel;
}

public String getMessageText() {
    return messageText;
}
}

结果是:

TEST1 (FATAL)
TEST2 (DEBUG)
TEST3 (FATAL)
TEST1 (FATAL)
TEST1 (FATAL)
TEST2 (DEBUG)
TEST3 (FATAL)
TEST2 (DEBUG)
TEST3 (FATAL)

最佳答案

一个明显的非答案:忘记这里使用 3 个线程。

The problem is that the output is not in order, and triple of what it should be. Instead of 3 messages I get 9.

当然。因为你要求三个 3 线程完成单个线程应该做的工作,并且每个线程又做同样的工作。

所以,首先:一旦你说“多线程”,并且谈论打印列表内容,那么所有关于排序的赌注都消失了。当然,每个线程都会按正确的顺序打印消息,但是您无法控制 T1 是先打印所有消息,还是只打印一条消息,然后从 T2 打印 3 条消息,等等。 “未同步”线程的本质是:未定义的顺序。

然后:即使您添加了必要的步骤来以某种方式“同步”您的线程,您也不会从中获得任何好处。

内存中有一个列表。有一个输出文件(或控制台)。使用多个线程来获取值并将它们放入文件中不会加快任何速度!它只会产生开销,正如所见:它产生了对大量“同步”代码的需求。

关于java - ArrayList 的多线程打印,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54171086/

相关文章:

java - JPA多对多关系中间表不更新

java - Arrays.binarySearch() 如何在不排序的情况下工作

c++ - 并发 C++11 - 可以使用哪些工具链?

Python:传递记录器是个好主意吗?

java - 定期调度定时器任务

java - 测验中的进度条 (Android Studio)

javascript - 如何使 `winston` 日志库像 `console.log` 一样工作?

c# - 如何在 .NET 中无一异常(exception)地打印当前堆栈跟踪?

java - java 序列中的服务(线程)

multithreading - Delphi 线程速度提升