线程在运行结束时不会自然退出()

我的问题是: 如何读取一个巨大的(数百万行)文件保持一个线程活着,即使它完成了文件的东西

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

我假设这是由于线程保留了一些我缺少的资源,但是,因为我使用的是try-with-resource模型,所以我不确定这是怎么回事。

这是引发线程的javafx控制器类(使用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类,因为它不是太大。 所有这一切确实要么转一行看起来像:yearmonthday到年,月,日,或者它将年月和日列分隔成单独的文件,如果用户点击了要求它的复选框。 只是一个用例的便利工具。

请注意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 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的部分原因在于资源尝试的疯狂,而另一种是更传统的方式,只是为了举例说明它已经尝试了两种方式,相同的症状来了通过任一逻辑块运行的线程,所以我很确定我关闭资源的方式与它无关。

编辑:不是说我可以快速阅读代码。 尝试这个。 我早点错过了什么。 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 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最佳实践,同时获取/关闭资源 .. overkill解决方案,但简单的Java io丑陋的try-finally块

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

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

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

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

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

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

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