Java 无法找出异常
我正在编写简单的代码,以异步方式将日志写入文件,但发现很难解决一个问题 我在Java 无法找出异常,java,android,multithreading,exception,concurrency,Java,Android,Multithreading,Exception,Concurrency,我正在编写简单的代码,以异步方式将日志写入文件,但发现很难解决一个问题 我在logNodes.removeFirst()中获得java.util.NoSuchElementException。如果我检查列表是否为空,怎么会发生这种情况 如果我经常登录,则通常会出现此问题 如果有人能向我解释为什么会发生这种情况,我将不胜感激 我的代码: private static class FileLogger extends Thread { private File logFile; pr
logNodes.removeFirst()
中获得java.util.NoSuchElementException
。如果我检查列表是否为空,怎么会发生这种情况
如果我经常登录,则通常会出现此问题
如果有人能向我解释为什么会发生这种情况,我将不胜感激
我的代码:
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;
}
}
}
私有静态类文件记录器扩展线程{
私有文件日志文件;
私人印刷撰稿人;
private final LinkedList logNodes=new LinkedList();
公共文件记录器(上下文){
String dateString=(String)DateFormat.format(“yyyy-MM-dd_HH:MM:ss”,new Date());
File logsDir=新文件(context.getCacheDir(),“logs”);
if(logsDir.exists()){
for(文件:logsDir.listFiles()){
delete();
}
}
试一试{
logFile=新文件(logsDir,dateString+“.log”);
如果(!logFile.exists()){
logFile.getParentFile().mkdirs();
logFile.createNewFile();
}
logWriter=newprintwriter(newfileoutputstream(logFile));
start();
}捕获(忽略IOException){
}
}
公共作废日志(日期、字符串标记、字符串消息){
if(isAlive()){
addLast(新的LogNode(日期、标记、消息));
已同步(此){
this.notify();
}
}
}
@凌驾
公开募捐{
while(true){
if(logNodes.isEmpty()){
试一试{
已同步(此){
这个。等等();
}
}捕捉(中断异常e){
logWriter.flush();
logWriter.close();
返回;
}
}否则{
LogNode node=logNodes.removeFirst();
SimpleDataFormat dateFormat=新的SimpleDataFormat(“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();
}
}
}
私有类日志节点{
最后日期;
最后的字符串标签;
最终字符串msg;
公共日志节点(日期、字符串标记、字符串消息){
this.date=日期;
this.tag=tag;
this.msg=msg;
}
}
}
原因
您没有同步多个日志线程
假设您有thread1和thread2:
thread1已将node1写入队列
FileLogger
在调用isEmpty
时注意到node1,而thread2注意到了
我没注意到
thread2认为此列表为空,让列表的
最后一个节点是node2,这意味着node1已被覆盖
由于您没有任何其他同步,node2可能不会被FileLogger
注意到,因此将抛出NoSuchElementException
解决方案
与其自己实现阻塞队列,不如尝试使用java.util.concurrent
提供的方法,让它为您执行同步
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;
}
}
}
}
私有静态类文件记录器扩展线程{
私有文件日志文件;
私人印刷撰稿人;
private final BlockingQueue logNodes=新建LinkedBlockingQueue();
公共文件记录器(上下文){
String dateString=(String)DateFormat.format(“yyyy-MM-dd_HH:MM:ss”,new Date());
File logsDir=新文件(context.getCacheDir(),“logs”);
if(logsDir.exists()){
for(文件:logsDir.listFiles()){
delete();
}
}
试一试{
logFile=新文件(logsDir,dateString+“.log”);
如果(!logFile.exists()){
logFile.getParentFile().mkdirs();
logFile.createNewFile();
}
logWriter=newprintwriter(newfileoutputstream(logFile));
start();
}捕获(忽略IOException){
}
}
公共作废日志(日期、字符串标记、字符串消息){
if(isAlive()){
添加(新的LogNode(日期、标记、消息));
}
}
@凌驾
公开募捐{
while(true){
试一试{
LogNode=logNodes.take();
SimpleDataFormat dateFormat=新的SimpleDataFormat(“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();
}捕捉(中断异常e){
logWriter.flush();
logWriter.close();
返回;
}
}
}
}
这看起来像是并发问题。您可以使用ExecutorService
(在您的情况下,a)将起作用,而不是自己处理线程和排队节点。您可以向它提交新节点,只需实现一个执行I/O部分的Runnable
。剩下的是免费的。谢谢你的解释和解决方案。现在看来工作还行。