Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 无法找出异常_Java_Android_Multithreading_Exception_Concurrency - Fatal编程技术网

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
    。剩下的是免费的。谢谢你的解释和解决方案。现在看来工作还行。