簡體   English   中英

來自 ArrayList 的多線程打印

[英]Multithreaded printing from ArrayList

我試圖讓記錄器將應用程序中的所有日志消息打印到控制台,並在將來打印外部文件。 當我觸發函數時它應該這樣做:“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)

每個線程應該運行不同的任務。 您實現了 run(),因此線程將遍歷所有消息,而不是讓每個線程處理大量消息。

為每個線程提供它應該寫入控制台的索引。 假設您要創建 3 個線程並且您有 12 條消息,那么:線程 1 將打印 0 到 3,線程 2 將打印 4 到 7,線程 3 將打印 8 到 11

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

public LoggingThread(CopyOnWriteArrayList messages, int start, int end) {
    this.messages = messages;
    this.start=start;
    this.end=end;
}

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

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

並創建您的日志:

thread1 = new LoggingThread(this.messages, 0, this.messages.length()/3);
thread2 = new LoggingThread(this.messages, this.messages/3, 2*(this.messages.length()/3));
thread3 = new LoggingThread(this.messages, 2*(this.messages.length()/3), this.messages.length());

每個線程都有三分之一的消息要打印。

關於順序……嗯,線程是同時運行的,所以你真的不知道哪個會先完成以及每個日志什么時候打印。

但是,您可以等待每個線程完成 - 在開始下一個之前。 這將使日志保持有序:

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

但是,使用三個線程是沒有意義的。

一個明顯的非答案:忘記在這里使用 3 個線程。

問題是輸出沒有按順序排列,而且是應該排列的三倍。 我收到 9 條消息,而不是 3 條消息。

當然。 因為你讓三個 3 線程做一個單線程應該做的工作,每個線程又做同樣的工作。

因此,首先:一旦您說“多線程”,並且您談到打印列表內容,那么所有關於訂購的賭注都將關閉。 當然,每個線程都會以正確的順序打印消息,但是您無法控制 T1 是先打印所有消息,還是只打印一個,然后是 T2 的 3 個,等等。 “未同步”線程的本質是:未定義的順序。

然后:即使您添加了必要的步驟以某種方式“同步”您的線程,您不會因此而獲得任何好處

內存中只有一個列表。 有一個輸出文件(或控制台)。 使用多個線程來獲取值並將它們放入您的文件中並不會加快任何速度! 它只會產生開銷,正如所見:它需要大量“同步”代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM