簡體   English   中英

字段超出范圍java

[英]field goes out of scope java

我對多線程應用程序有一些問題。 我想從類似CSV的文件中加載數據,並將其存儲在緩沖區中以供以后檢索。

似乎當線程結束(?)時動物列表超出范圍了,我不了解Java線程的某些知識,將不勝感激。

調用方式:

ParseCSV parser = new ParseCSV(null);
EventQueue.invokeLater(parser);
System.err.println("printing!");

編輯-根據要求,這是失敗的部分-praser緩沖區的內容此時為空。 我以為如果我在解析器中使用new關鍵字,動物的內容將是持久的。

while(parser.hasNext()){
    System.err.println("#");
    System.err.println(parser.getNext().toString());
}

解析器類:

public class ParseCSV implements Runnable{

    private String path = null;
    private File file = null;
    private static Logger log = LogManager.getLogger(ParseCSV.class.getName());
    private volatile ArrayList<Animal> animals = new ArrayList<Animal>();
    private int pointer =0;



    public ParseCSV(String path) {
        animals = new ArrayList<Animal>(); //tried to reinitialize, didn't help this is where the problem occurs
        if(path == null){
            JFileChooser jfc = new JFileChooser();
            jfc.showOpenDialog(null);
            file = jfc.getSelectedFile();
            this.path = file.getAbsolutePath();
        }
        else {
            this.path = path;

        }
        log.debug("Initialized file parser for " + this.path);
    }

    @Override
    public void run() {
        log.debug("begining file parse");
        System.err.println("runnner");
        try {
            Scanner fileScan = new Scanner(this.file);
            while(fileScan.hasNextLine()){
                parseLine(fileScan.nextLine());
            }
            fileScan.close();
        } catch (FileNotFoundException e) {
            log.error("Exception occured: " + e.getMessage() + "\nstack:\n" + e.getStackTrace());
            System.err.println("Exception: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private void parseLine(String nextLine) {
        Scanner lineScanner = new Scanner(nextLine);
        lineScanner.useDelimiter("\\s\\|\\s");
        if(lineScanner.hasNext()){
            Animal an =             new Animal(lineScanner.next(), //person
                    lineScanner.next(), //animal
                    Integer.parseInt(lineScanner.next()), //emp-number
                    lineScanner.next(), //date
                    Integer.parseInt(lineScanner.next()), //ani-number
                    lineScanner.next());
            animals.add(an);    //contract ID
            System.err.println(an.toString()); //prints correct result!
        }
        lineScanner.close();
    }

    public String getPath() {       return path;    }
    public void setPath(String path) {      this.path = path;   }

    public boolean hasNext(){
        System.err.println("size of data = " + animals.size());
        if(animals.size() == pointer || animals.isEmpty()) return false;
        else return true;
    }
    public Sale getNext(){
        if(animals.size() == pointer) return null;
        return animals.get(pointer++);

    }

}

編輯-添加注釋以指出問題出現的位置

您需要等待解析器線程完成(當前兩者同時發生),這可能是程序不打印任何內容的原因。 您可以嘗試添加一些日志記錄語句,然后檢查序列是否正確。

EventQueue#invokeLater將任務添加到事件隊列中,因此在進入下一行時可能無法完成。 請改用EventQueue#invokeAndWait ,它等待任務完成。

您的代碼有一些問題。 其中一些實際上導致了問題,而另一些只是表明您並不真正了解自己要做什么。

private volatile ArrayList<Animal> animals = new ArrayList<Animal>();

為什么在此上使用volatile? 每個線程都有自己的動物列表,因此它們僅由一個線程使用。 如果您的主類具有每個人都添加的動物模型,則需要使其具有可變性,因為多個線程可以訪問它。

    animals = new ArrayList<Animal>(); //tried to reinitialize, didn't help this is where the problem occurs

這不會改變任何東西。 如果您認為該方法可以多次調用並且每次都想要一個新列表,則可能會很有用,但是這可能只是浪費。

現在到真正的問題:

調用線程時,是因為您希望它在后台運行,而不是停止主程序執行。 然后,您可以在實際完成的某個時間返回結果。 正如人們所說的,如果您只想要一個新線程而又不真正在后台運行,則可以執行EventQueue#invokeAndWait,但對於您而言,這不是解決方案。

您可以使用觀察者模式。 為此,您需要創建一個具有notify方法的接口(將其稱為parseListner或其他名稱)。 解析器具有parseListerners的列表。 解析器完成解析后,它會告訴所有偵聽器(通過在接口上調用方法)。 因此,您最終得到的是這樣的代碼:

public interface ParseListner{
   void fileParsed(String fileName, List<Animal> animals);
}

public class Main implements ParseListner{
   public void main(){
      ParseCSV parser = new ParseCSV(this);
      EventQueue.invokeLater(filePath, parser);
   }
   public void fileParsed(String fileName, List<Animal> animals){
      System.Out.Println(doneParsing);
   }
}

公共類ParseCSV實現Runnable {List listners = new ArrayList <>(); 公共ParseCSV(字符串路徑,ParseListner調用方){listner.add(caller)}

@Override
public void run() {
    //all the parsestuff
    for(ParseListner p : listners)
       p.parsedFile(fileName, animals);
}

我使用了一個列表,因為它幾乎總是有用的(因此完成后您可以做很多事情)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM