ArrayList 的多线程打印
Multithreaded printing from ArrayList
我正在尝试让记录器将所有日志消息从应用程序打印到控制台,并在将来打印到外部文件。当我触发函数时它应该这样做:"dumpToConsole"。它应该通过 3 个线程多线程完成,所有 3 个线程都访问 CopyOnWriteArrayList。问题是输出没有按顺序排列,是应该输出的三倍。我得到 9 条消息而不是 3 条消息。例如,我需要 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();
}
}
还有我的留言class:
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 个线程并且你有 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());
每个线程打印三分之一的消息。
关于顺序...好吧,关于线程的事情是它们同时 运行ning,所以你无法真正知道哪个先完成以及每个日志何时打印。
但是,您可以等待每个线程完成 - 然后再开始下一个。这将使日志保持有序:
thread1.start();
thread1.join();
thread2.start();
thread2.join();
thread3.start();
thread3.join();
但是使用三个线程就没有意义了。
一个明显的非答案:忘记在这里使用 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线程去做一个线程应该做的工作,而每个线程又做同样的工作。
所以,首先:一旦你说 "multi threading",并且你谈论打印列表内容,那么所有关于排序的赌注都会被取消。当然,每个线程都会以正确的顺序打印消息,但是您可以 no 控制 T1 是先打印所有消息,还是只打印一条消息,然后再打印来自 T2 的 3 条消息,等等。 "un sync'ed" 线程的本质是:undefined order。
然后:即使您以某种方式向您的线程添加了必要的步骤 "sync up",您这样做也一无所获。
内存中有一个列表。有一个输出文件(或控制台)。使用多个线程来获取值并将它们放入文件不会加快任何速度!它只会产生开销,正如所见:它需要大量 "sync" 代码。
我正在尝试让记录器将所有日志消息从应用程序打印到控制台,并在将来打印到外部文件。当我触发函数时它应该这样做:"dumpToConsole"。它应该通过 3 个线程多线程完成,所有 3 个线程都访问 CopyOnWriteArrayList。问题是输出没有按顺序排列,是应该输出的三倍。我得到 9 条消息而不是 3 条消息。例如,我需要 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();
}
}
还有我的留言class:
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 个线程并且你有 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());
每个线程打印三分之一的消息。
关于顺序...好吧,关于线程的事情是它们同时 运行ning,所以你无法真正知道哪个先完成以及每个日志何时打印。
但是,您可以等待每个线程完成 - 然后再开始下一个。这将使日志保持有序:
thread1.start();
thread1.join();
thread2.start();
thread2.join();
thread3.start();
thread3.join();
但是使用三个线程就没有意义了。
一个明显的非答案:忘记在这里使用 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线程去做一个线程应该做的工作,而每个线程又做同样的工作。
所以,首先:一旦你说 "multi threading",并且你谈论打印列表内容,那么所有关于排序的赌注都会被取消。当然,每个线程都会以正确的顺序打印消息,但是您可以 no 控制 T1 是先打印所有消息,还是只打印一条消息,然后再打印来自 T2 的 3 条消息,等等。 "un sync'ed" 线程的本质是:undefined order。
然后:即使您以某种方式向您的线程添加了必要的步骤 "sync up",您这样做也一无所获。
内存中有一个列表。有一个输出文件(或控制台)。使用多个线程来获取值并将它们放入文件不会加快任何速度!它只会产生开销,正如所见:它需要大量 "sync" 代码。