2015-05-20 91 views
3

我有以下代碼,剛剛得到ConcurrentModificationException。如何避免從JFileChooser.setFileFilter()調用ConcurrentModificationException?

fchProtocol = new FileChooser(lastFileLoc); 
FileNameExtensionFilter xmlfilter = new FileNameExtensionFilter("xml files (*.xml)", "xml"); 
fchProtocol.setFileFilter(xmlfilter); <<<< ***** exception from here 

的異常跟蹤信息:

java.util.ConcurrentModificationException 
    java.util.Vector$Itr.checkForComodification(Vector.java:1184) 
    java.util.Vector$Itr.next(Vector.java:1137) 
    javax.swing.plaf.basic.BasicDirectoryModel$LoadFilesThread.cancelRunnables(BasicDirectoryModel.java:340) 
    javax.swing.plaf.basic.BasicDirectoryModel$LoadFilesThread.cancelRunnables(BasicDirectoryModel.java:346) 
    javax.swing.plaf.basic.BasicDirectoryModel.validateFileCache(BasicDirectoryModel.java:135) 
    javax.swing.plaf.basic.BasicDirectoryModel.propertyChange(BasicDirectoryModel.java:69) 
    java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:335) 
    java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:327) 
    java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:263) 
    java.awt.Component.firePropertyChange(Component.java:8422) 
    javax.swing.JFileChooser.setFileFilter(JFileChooser.java:1473) 

這是Java API方法的代碼。它是最後一行拋出異常。

public void setFileFilter(FileFilter filter) { 
     FileFilter oldValue = fileFilter; 
     fileFilter = filter; 
     if (filter != null) { 
      if (isMultiSelectionEnabled() && selectedFiles != null && selectedFiles.length > 0) { 
       Vector<File> fList = new Vector<File>(); 
       boolean failed = false; 
       for (File file : selectedFiles) { 
        if (filter.accept(file)) { 
         fList.add(file); 
        } else { 
         failed = true; 
        } 
       } 
       if (failed) { 
        setSelectedFiles((fList.size() == 0) ? null : fList.toArray(new File[fList.size()])); 
       } 
      } else if (selectedFile != null && !filter.accept(selectedFile)) { 
       setSelectedFile(null); 
      } 
     } 
     firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, oldValue, fileFilter); 
    } 

這發生在GUI初始化階段。並且xmlfileter是一個局部變量。我正在使用javaVersion = 1.8.0_20在Linux中。這是不可複製的,今年在我的開發過程中只發生過三次。

我不知道如何避免這種情況,或者如何正確使用FileChooser及其FileFilter。任何人都可以幫助我?

編輯:

它發生在應用程序初始化階段:

  1. 主線程與開始主()
  2. 在主線程
  3. 初始化幾個非GUI類;
  4. 致電

SwingUtilities.invokeAndWait(new Runnable() 

    public void run() 
    {  
     initalize GUI classes from here  
    }  
); 

做GUI初始化,但在初始化線程在前幾個步驟失敗。 GUI初始化線程中沒有其他線程。而且主線程沒有訪問GUI初始化線程的動作。

那時基本有兩個線程:主線程和GUI初始化線程通過invorkAndWait()調用啓動。

+2

你可以發佈[MCVE](http://stackoverflow.com/help/mcve)嗎?我知道你說這是不可複製的,這會使它很難提供幫助。你在做什麼線程嗎? –

+3

也許https://bugs.openjdk.java.net/browse/JDK-8068244 – copeg

+0

我的印象是堆棧跟蹤不完整。你可以發佈一個完整的嗎? – geert3

回答

1

如果你在除事件調度線程之外的其他線程上執行GUI,這種類型的東西總是在Swing中發生。特別是「不可重現」是一條線索。這是併發線程處理GUI的計時問題,而只有EDT應該這樣做。有關更多信息,請參閱here。 所以包裝GUI相關的東西在SwingUtilities.invokeLater,你的情況:

final FileFilter oldValue = fileFilter; 
... 
SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
     firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, oldValue, fileFilter); 
    } 
}); 
+0

firePropertyChanged()方法屬於JAVA API。我無法對其做任何改變。 – peterboston

+0

ok同意。我很愚蠢。但事實依然是,既不可重現又不協調的錯誤提示暗示你的代碼會干擾EDT。 – geert3

+0

@peterboston invokeAndWait必須從EDT中調用,您必須從isEventDispatchThread測試false,否則使用invoekLater(簡單的if-else) – mKorbel

0

不是一個真正的答案,但可以證明給別人打這個問題非常有用。

這絕對是從2014年開始的https://bugs.openjdk.java.net/browse/JDK-8068244的體現。剛剛發生在Java 9.0.1/Windows 10上,在JFrame構造函數中拋出EDT,與OP描述的非常相似。

java.util.ConcurrentModificationException 
    at java.base/java.util.Vector$Itr.checkForComodification(Unknown Source) 
    at java.base/java.util.Vector$Itr.next(Unknown Source) 
    at java.desktop/javax.swing.plaf.basic.BasicDirectoryModel$FilesLoader.cancelRunnables(Unknown Source) 
    at java.desktop/javax.swing.plaf.basic.BasicDirectoryModel$FilesLoader.cancelRunnables(Unknown Source) 
    at java.desktop/javax.swing.plaf.basic.BasicDirectoryModel.validateFileCache(Unknown Source) 
    at java.desktop/javax.swing.plaf.basic.BasicDirectoryModel.propertyChange(Unknown Source) 
    at java.desktop/java.beans.PropertyChangeSupport.fire(Unknown Source) 
    at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(Unknown Source) 
    at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(Unknown Source) 
    at java.desktop/java.awt.Component.firePropertyChange(Unknown Source) 
    at java.desktop/javax.swing.JFileChooser.setFileFilter(Unknown Source) 
    at com.example.ExampleJFrame.initFileChoosers(Unknown Source) 
    at com.example.ExampleJFrame.<init>(Unknown Source) 
    at com.example.ExampleJFrame$15.run(Unknown Source) 
    at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source) 
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source) 
    at java.desktop/java.awt.EventQueue.access$500(Unknown Source) 
    at java.desktop/java.awt.EventQueue$3.run(Unknown Source) 
    at java.desktop/java.awt.EventQueue$3.run(Unknown Source) 
    at java.base/java.security.AccessController.doPrivileged(Native Method) 
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source) 
    at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source) 
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) 
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) 
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) 
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source) 
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source) 
    at java.desktop/java.awt.EventDispatchThread.run(Unknown Source) 

,導致它被適當地在EDT通過SwingUtilities.invokeLater()在堆棧跟蹤作爲明顯執行的代碼。initFileChoosers()方法僅實例化幾個文件選擇器,爲它們調用setFileFilter(),有時多次按順序。

當然不能複製。