线程在运行结束时不会自然退出() [英] Thread won't naturally exit at end of run()

查看:106
本文介绍了线程在运行结束时不会自然退出()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是这样的:如何读取一个巨大的(数百万行)文件,即使在完成文件填充之后仍保持活动

问题是我有一个从javafx应用程序线程启动的线程,然后(新线程)对文本文件执行一些读/写操作,当面对要解析的HUGE文件时不会自然退出通过,特别是1700万行。

The problem is that I have a Thread started from the javafx application thread, which then (the new thread) performs some read/write actions on a text file, won't exit naturally when faced with HUGE files to parse through, 17-million lines large, specifically.

我假设这是由于线程持有某些我缺少的资源,但是,因为我正在使用try-with-resource模型,我不确定这是怎么回事。

I'm assuming this is due to the thread holding on to some resource that I'm missing, however, since I'm using the try-with-resource model, I'm not sure how that's even possible really.

这是引发线程的javafx控制器类(使用fxml):

Here's the javafx controller class (using fxml) that sparks off the thread:

MainController.java:

MainController.java:

    /**
     * This method handles what happens when the calculate button is clicked.
     * The main thing this does is disable/enable a few Nodes, as well as sparks
     * off the background thread.
     *
     * @param event
     */
    @FXML
    private void convert_button_action(ActionEvent event) {
        closing_label.setVisible(true);
        convert_button.setDisable(true);
        input_text = input_NCLocation_field.getText();
        output_text = output_Location_Field.getText();
        indicator_node.setVisible(true);

        if (!toggleSwitch.isSelected()) {
            (new Thread(new FileWriter(input_text, output_text, indicator_node))).start();
        } else {
            DateWriter temp = new DateWriter(input_text, output_text, indicator_node, yr_mn_dy.isSelected());
            (new Thread(temp)).start();
        }

    }

那里没什么特别的,只是一些使事物可见/不可见,并根据用户的输入启动适当的线程。接下来是整个Thread类,因为它不是太大。所有这一切确实要么转一行看起来像:yearmonthday到年,月,日,或者它将年月和日列分隔成单独的文件,如果用户点击了要求它的复选框。只是一个用例的便利工具。

nothing too fancy in there, simply some making things visible/not visible and the starting of the appropriate thread based on the input of the user. next is the entire Thread class since it's not too huge. All it does really is either turn a line that looks like: yearmonthday into year,month,day or it separates the year month and day columns into separate files if the user clicked the check box that asked for it. Simply a handy tool for the use case.

请注意 run()方法末尾的println语句。我每次都会看到这个println,但在它发生之后,没有任何反应。程序没有退出,线程没有停止,没有。

Please note the println statement at the end of the run() method. I see this println every single time, but after it happens, nothing happens. The program doesn't exit, the thread doesn't stop, nothing.

package File_Conversion;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.scene.control.ProgressIndicator;

/**
 * This class is the background 'worker' thread that does all of the heavy duty
 * file IO for splitting up the NC file. It periodically sends reports back to
 * the main application thread to update the progress indicator.
 *
 * @author William
 */
public class DateWriter implements Runnable {

    private final ProgressIndicator myIndicator;
    private static File ncFile;
    private final String outputLocationFile;
    private float zmax, zmin, xmax, xmin, ymax, ymin;
    private ArrayList<Float> xList, yList, zList;
    private final DecimalFormat numberFormat = new DecimalFormat("#.000000");
    private final DecimalFormat numberFormatMinMax = new DecimalFormat("#.00000");
    private final boolean yr_mon_day;

    /**
     * This is the main constructor, it needs a valid NC file to continue.
     *
     * @param inputNCFile
     * @param outputLocation
     * @param myIndicator
     * @param yr_mon_day
     */
    public DateWriter(String inputNCFile, String outputLocation, ProgressIndicator myIndicator, boolean yr_mon_day) {
        this.yr_mon_day = yr_mon_day;
        this.myIndicator = myIndicator;
        ncFile = new File(inputNCFile);
        outputLocationFile = outputLocation;

    }

    /**
     * The primary run() method, starts the thread.
     */
    @Override
    public void run() {
        convertDate();
        Platform.runLater(new Runnable() {

            @Override
            public void run() {
                File_Conversion.stage_returner().close();
            }

        });
        System.out.println("I'm at the end of the run...??");
    }

    public boolean convertDate() {

        BufferedReader br = null;
        java.io.FileWriter yearWriter = null, MonthWriter = null, DayWriter = null
                            ,fWriter = null;
        BufferedWriter yearBuf = null, monthBuf = null, dayBuf = null, writer = null;


        try {
                br = new BufferedReader(new FileReader(ncFile));
                if (yr_mon_day) {
                yearWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName().substring(0, ncFile.getName().lastIndexOf(".")) + "_modified_year.csv", false);
                yearBuf = new BufferedWriter(yearWriter);
                MonthWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName().substring(0, ncFile.getName().lastIndexOf(".")) + "_modified_month.csv", false);
                monthBuf = new BufferedWriter(MonthWriter);
                DayWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName().substring(0, ncFile.getName().lastIndexOf(".")) + "_modified_day.csv", false);

                dayBuf = new BufferedWriter(DayWriter);
                String input;
                String temp;
                String temp2;
                String temp3;
                while ((input = br.readLine()) != null) {
                    temp = input.substring(0, 4);

                    temp2 = input.substring(4, 6);

                    temp3 = input.substring(6);
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            myIndicator.setProgress(-1);
                        }
                    });
                    yearBuf.write(temp + "\n");
                    monthBuf.write(temp2 + "\n");
                    dayBuf.write(temp3 + "\n");
                }

            } else {
                fWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName() + "_modified.csv", false);
                writer = new BufferedWriter(fWriter);
                String input;
                String temp;
                while ((input = br.readLine()) != null) {
                    temp = input.substring(0, 4) + "," + input.substring(4, 6) + "," + input.substring(6);
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            myIndicator.setProgress(-1);
                        }
                    });
                    writer.write(temp + "\n");
                }

            }
        } catch (IOException e) {
            e.printStackTrace(System.out);
        }finally{
            try{
                if (br!=null) br.close();
                if (yearBuf !=null) yearBuf.close();
                if (monthBuf != null)monthBuf.close();
                if (dayBuf != null)dayBuf.close();
                if (yearWriter != null)yearWriter.close();
                if (MonthWriter != null)MonthWriter.close();
                if (DayWriter != null)DayWriter.close();
                if (fWriter != null) fWriter.close();
                if (writer != null) writer.close();

            }catch(IOException e){
                e.printStackTrace(System.out);
            }
        }

        return true;
    }

}

再次,没什么特别的,有些是缓冲的流和作家,就是这样!值得注意的是,这适用于小型/非大型文件。只有在面对数百万行文件时,我才会看到这种行为。

again, nothing fancy, some buffered streams and writers, and that's it! It's worth noting that this works perfectly for files that are small/not gigantic. It was only when faced with a multi-million line file am I seeing this behaviour.

非常感谢您提供的任何帮助,谢谢!

Any help you can give would be much appreciated, thanks!

编辑1

为了帮助澄清,if / else的部分原因在于资源尝试疯狂,另一种是更传统的方式,简单来说就是为了举例说明它已经尝试了两种方式,相同的症状出现在通过任一逻辑块的线程中,所以我很确定我关闭资源的方式与它无关。

Just to help clarify, the reason part of the if/else is in try-with-resource madness, and the other is in the more traditional fashion, is simply to exemplify the fact that it has been tried both ways, the identical symptoms come out the thread running through either of the logical blocks, so I'm fairly certain the way I'm closing the resources has nothing to do with it.

推荐答案

所以事实证明这是一个解决方案我昨天有一个想法,但从未采取行动。

So this turned out to be a solution I had a hint of a thought about yesterday, but never acted on.

基本上我遇到的问题的根源(我认为)是由于超出了我的写缓冲区,导致了未定义的行为。

Essentially the root of the problem I was encountering (I think) was due to overrunning my write buffer, which was causing undefined behaviour.

现在,我不知道这是因为java bufferedwriter的java实现不好,还是究竟发生了什么,但解决方案原来是相对简单:现在冲洗流每次迭代,我知道你在想什么,Gah!经常这样!减速必须是巨大的!是的确,减速速度非常快,它使得一个1700万行文件解析从大约14秒到大约4分钟。

Now, I don't know if this is because of a bad java implementation of the java bufferedwriter, or what is exactly going on, but the solution turned out to be relatively simple: flush the streams every single iterations now, I know what you're thinking, Gah! that's so often! the slowdown must be immense! yes indeed, the slowdown WAS immense, it made a 17-million line file parse go from taking around 14 seconds, to around 4 minutes.

我可以略微提高刷新次数以提高性能,但每10次迭代冲洗一次,它仍然会破坏。

It's possible I could slightly up the iterations on the flushes to improve performance, but with a flush every 10 iterations, it still broke.

我确信这是在java中处理读/写操作和内存管理内部的结果,我没有时间深入研究它。如果有人想花时间并对这种行为给出一个很好的解释,我会非常乐意将我接受的答案换成他们的帖子,因为它更完整。

I'm sure this is a result of how the internals of read/write operations and memory management are handled in java, and I don't have time to delve into it. If anyone wants to take the time and give a good explanation of this behaviour, I'll be more than happy to switch my accepted answer to their post, since it is more complete.

未来检查的固定(现在正在工作) DateWriter 类的代码:

The code of the fixed (and working now) DateWriter class for future inspection:

package File_Conversion;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.scene.control.ProgressIndicator;

/**
 * This class is the background 'worker' thread that does all of the heavy duty
 * file IO for splitting up the NC file. It periodically sends reports back to
 * the main application thread to update the progress indicator.
 *
 * @author William
 */
public class DateWriter implements Runnable {

    private final ProgressIndicator myIndicator;
    private static File ncFile;
    private final String outputLocationFile;
    private float zmax, zmin, xmax, xmin, ymax, ymin;
    private ArrayList<Float> xList, yList, zList;
    private final DecimalFormat numberFormat = new DecimalFormat("#.000000");
    private final DecimalFormat numberFormatMinMax = new DecimalFormat("#.00000");
    private final boolean yr_mon_day;

    /**
     * This is the main constructor, it needs a valid NC file to continue.
     *
     * @param inputNCFile
     * @param outputLocation
     * @param myIndicator
     * @param yr_mon_day
     */
    public DateWriter(String inputNCFile, String outputLocation, ProgressIndicator myIndicator, boolean yr_mon_day) {
        this.yr_mon_day = yr_mon_day;
        this.myIndicator = myIndicator;
        ncFile = new File(inputNCFile);
        outputLocationFile = outputLocation;
    }

    /**
     * The primary run() method, starts the thread.
     */
    @Override
    public void run() {
        convertDate();
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                File_Conversion.stage_returner().close();
            }
        });
        System.out.println("At the end of the method.");

    }

    public boolean convertDate() {

        BufferedReader br = null;
        java.io.FileWriter yearWriter = null, monthWriter = null, dayWriter = null, fWriter = null;
        BufferedWriter yearBuf = null, monthBuf = null, dayBuf = null, writer = null;
        try {
            br = new BufferedReader(new FileReader(ncFile));
            if (yr_mon_day) {
                yearWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName().substring(0, ncFile.getName().lastIndexOf(".")) + "_modified_year.csv", false);
                yearBuf = new BufferedWriter(yearWriter);
                monthWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName().substring(0, ncFile.getName().lastIndexOf(".")) + "_modified_month.csv", false);
                monthBuf = new BufferedWriter(monthWriter);
                dayWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName().substring(0, ncFile.getName().lastIndexOf(".")) + "_modified_day.csv", false);

                dayBuf = new BufferedWriter(dayWriter);
                String input;
                String temp;
                String temp2;
                String temp3;
                while ((input = br.readLine()) != null) {
                    temp = input.substring(0, 4);

                    temp2 = input.substring(4, 6);

                    temp3 = input.substring(6);
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            myIndicator.setProgress(-1);
                        }
                    });
                    yearBuf.write(temp + "\n");
                    monthBuf.write(temp2 + "\n");
                    dayBuf.write(temp3 + "\n");
                    yearBuf.flush();
                    monthBuf.flush();
                    dayBuf.flush();
                    temp = null;
                    temp2 = null;
                    temp3 = null;

                }
            } else {
                fWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName() + "_modified.csv", false);
                writer = new BufferedWriter(fWriter);
                String input;
                String temp;
                while ((input = br.readLine()) != null) {
                    temp = input.substring(0, 4) + "," + input.substring(4, 6) + "," + input.substring(6);
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            myIndicator.setProgress(-1);
                        }
                    });
                    writer.write(temp + "\n");
                    writer.flush();

                }

            }
        } catch (IOException e) {
            e.printStackTrace(System.out);
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
                if (yearBuf != null) {
                    yearBuf.close();
                }
                if (monthBuf != null) {
                    monthBuf.close();
                }
                if (dayBuf != null) {
                    dayBuf.close();
                }
                if (yearWriter != null) {
                    yearWriter.close();
                }
                if (monthWriter != null) {
                    monthWriter.close();
                }
                if (dayWriter != null) {
                    dayWriter.close();
                }
                if (fWriter != null) {
                    fWriter.close();
                }
                if (writer != null) {
                    writer.close();
                }

            } catch (IOException e) {
                e.printStackTrace(System.out);
            }
        }
        return true;
    }

}

这篇关于线程在运行结束时不会自然退出()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆