我正在编写简单的代码到异步将日志写入文件,但发现很难找出一个问题。
我在java.util.NoSuchElementException
中获得logNodes.removeFirst()
。如果我检查列表是否为空,怎么会发生这种情况?
如果我经常登录,则会出现此问题。
如果有人能向我解释为什么会发生这种情况,我们将非常感激。
我的代码:
private static class FileLogger extends Thread {
private File logFile;
private PrintWriter logWriter;
private final LinkedList<LogNode> logNodes = new LinkedList<>();
public FileLogger(Context context) {
String dateString = (String) DateFormat.format("yyyy-MM-dd_HH:mm:ss", new Date());
File logsDir = new File(context.getCacheDir(), "logs");
if (logsDir.exists()) {
for (File file : logsDir.listFiles()) {
file.delete();
}
}
try {
logFile = new File(logsDir, dateString + ".log");
if (!logFile.exists()) {
logFile.getParentFile().mkdirs();
logFile.createNewFile();
}
logWriter = new PrintWriter(new FileOutputStream(logFile));
start();
} catch (IOException ignored) {
}
}
public void log(Date date, String tag, String msg) {
if (isAlive()) {
logNodes.addLast(new LogNode(date, tag, msg));
synchronized (this) {
this.notify();
}
}
}
@Override
public void run() {
while (true) {
if (logNodes.isEmpty()) {
try {
synchronized (this) {
this.wait();
}
} catch (InterruptedException e) {
logWriter.flush();
logWriter.close();
return;
}
} else {
LogNode node = logNodes.removeFirst();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
logWriter.println(String.format(
"%s %s.%s", dateFormat.format(node.date), node.tag, node.msg
));
logWriter.flush();
}
}
}
private class LogNode {
final Date date;
final String tag;
final String msg;
public LogNode(Date date, String tag, String msg) {
this.date = date;
this.tag = tag;
this.msg = msg;
}
}
}
答案 0 :(得分:1)
您没有同步多个log
个主题。
假设你有thread1和thread2:
FileLogger
在调用isEmpty
时注意到了node1,而thread2则调用了{1}}
没注意到它。FileLogger
可能不会注意到node2,因此会引发NoSuchElementException
。请自行实施阻止队列,尝试使用java.util.concurrent
提供的BlockigQueue
,让它为您执行同步。
private static class FileLogger extends Thread {
private File logFile;
private PrintWriter logWriter;
private final BlockingQueue<LogNode> logNodes = new LinkedBlockingQueue<>();
public FileLogger(Context context) {
String dateString = (String) DateFormat.format("yyyy-MM-dd_HH:mm:ss", new Date());
File logsDir = new File(context.getCacheDir(), "logs");
if (logsDir.exists()) {
for (File file : logsDir.listFiles()) {
file.delete();
}
}
try {
logFile = new File(logsDir, dateString + ".log");
if (!logFile.exists()) {
logFile.getParentFile().mkdirs();
logFile.createNewFile();
}
logWriter = new PrintWriter(new FileOutputStream(logFile));
start();
} catch (IOException ignored) {
}
}
public void log(Date date, String tag, String msg) {
if (isAlive()) {
logNodes.add(new LogNode(date, tag, msg));
}
}
@Override
public void run() {
while (true) {
try {
LogNode node = logNodes.take();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
logWriter.println(String.format(
"%s %s.%s", dateFormat.format(node.date), node.tag, node.msg
));
logWriter.flush();
} catch (InterruptedException e) {
logWriter.flush();
logWriter.close();
return;
}
}
}
}