java - 线程不会在 run() 结束时自然退出

标签 java multithreading javafx-2

我的问题是这样的:读取一个巨大的(数百万行)文件如何使线程保持 Activity 状态,即使它完成了文件操作

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

我假设这是由于线程保留了我缺少的某些资源,但是,由于我使用的是 try-with-resource 模型,我不确定这实际上是如何可能的。

这是引发线程的 javafx Controller 类(使用 fxml):

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 类,因为它不是太大。它所做的只是将看起来像这样的行: 年月日 转换为年、月、日,或者如果用户单击了要求的复选框,则将年月和日列分隔成单独的文件。只是针对用例的方便工具。

请注意 run() 方法末尾的 println 语句。我每次都会看到这个 println,但是发生之后什么也没有发生。程序没有退出,线程没有停止,什么也没有。

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;
    }

}

再说一次,没什么花哨的,一些缓冲流和编写器,就是这样!值得注意的是,这非常适合小/不是很大的文件。只有当面对数百万行文件时我才会看到这种行为。

如果您能提供任何帮助,我们将不胜感激,谢谢!

编辑 1

只是为了帮助澄清,if/else 的原因部分是尝试资源疯狂,而另一个是更传统的方式,只是为了举例说明它已经尝试过两种方式的事实,通过任一逻辑 block 运行的线程都会出现相同的症状,因此我相当确定关闭资源的方式与它无关。

最佳答案

编辑:并不是说我可以快速阅读代码。尝试这个。我之前错过了一些事情。 join() 只是等待它完成工作。我们需要稍后调用 stop() 或等效函数。 stop() 已被弃用,这就是为什么我仍然推荐线程池。 Executors.newCachedThreadPool() 应该可以解决问题。

Thread t=new Thread();
t.join();
t.stop();

旧的解决方案(也许有用): 确保线程终止的最简单方法是使用 Executors 和 ExecutorService

ExecutorService executorService = Executors.newFixedThreadPool(10);

executorService.execute(myRunnable);//execute right now
executorService.submit(myRunnable);//execute when <10 threads active
Future<MyType> future = executorService.submit(myCallable);//Runnable and Callable are efficient
MyType result = future.get();

executorService.submit(myThread);//more expensive to create threads and you are using a thread pool anyways

executorService.shutdown();//don't forget to do this when you are done executing or the program may hang

使用 Runnable 来简单地执行线程中的工作。当您需要返回结果时,请使用 Callable。

另一种方法是调用myThread.join();

第三种方法:SwingUtils.invokeLater(myRunnable);//最简单

编辑: 清理 try-catch 的解决方案: Java try/catch/finally best practices while acquiring/closing resources ..过度的解决方案,但很简单 Java io ugly try-finally block

关于java - 线程不会在 run() 结束时自然退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24253298/

相关文章:

java - BasicDataSource 的转换异常

java - 将对象保存在另一个对象中时出现 Hibernate getHibernateTemplate 问题

ruby-on-rails - 通过系统调用在 ruby​​ 中嵌套超时的问题

java - 将整数(非字符串)数据插入 JavaFX2 TableView

java - 使用 SSHj 进行 SSH 端口转发

java - 使用构造函数作为方法参数

python - .Semaphore() 和 .BoundedSemaphore() 有什么区别?

C++11 线程与异步性能(VS2013)

java - 使用 HTML 格式化 JavaFX ListView

java - 如何为 OSX 编译 .app 包