Java - SwingWorker - 如何在 EDT 中使用发布的数组列表
Java - SwingWorker - How to use an arraylist from publish in the EDT
访问正在另一个线程 (SwingWorker) 中处理的列表时如何避免 java.util.ConcurrentModificationException
?
我正在尝试使用的详细信息:
一个 GUI class,其中包含此 "main" 方法,我认为应该 运行 在 EDT 上。
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new myGUIwithButton();
}
});
}
这个 GUI 有一个绘制方法,它获取 Words
的列表,一个包含字符串和坐标的 class,并显示它们:
public void paint(final List<Word> words){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// prepare GUI's background, then :
for(Word word : words){ // <-- this is line 170 in the error shown below
// show each word in the GUI
// note that I'm not modifying the words list here
}
在 GUI 中按下按钮时,将执行 class 扩展 SwingWorker<List<Word>,List<Word>>
的实例。据我所知,这会创建工作线程。重写的doInBackground
方法创建一个单词列表,然后定期发布它:
public List<Word> doInBackground() {
List<Word> words = new ArrayList<Word>();
while (!isCancelled()) {
// do some work, define aNewWord
words.add( aNewWord );
publish(words);
Thread.pause(someTime);
}
return words;
}
然后自动将发布的单词发送到重写的process
方法:
protected void process(List< List<Word> > wordss) { // Executed on EDT ! <3
// I'm taking only the first list that was published to avoid trouble
List<Word> words = wordss.get(0);
myGUI.paint(words);
}
有什么问题?
当工作线程进入"fast"(停顿少于 50 毫秒)时,我经常在 paint
方法中的第 170 行遇到异常(GUI 文件称为 MotsFleches.java):
Exception in thread "AWT-EventQueue-1" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at MotsFleches.run(MotsFleches.java:170)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at org.GNOME.Accessibility.AtkWrapper.dispatchEvent(AtkWrapper.java:700)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
paint
方法中的 words
列表似乎在 EDT 处理它时被修改。我没有在那里修改它,所以它必须来自其他线程?
我认为该列表只是另一个线程中 words
列表的 "snapshot",因为它是使用 publish
方法发送的。显然不是。
那么我应该更改什么才能在 EDT 方法中使用 SwingWorker
中已发布列表的 "snapshot"?
感谢您提供的任何建议。
备注
- 异常后,程序保持运行ning正常。我只想让它更干净。
- 我试着查看 Collections.synchronizedList() 甚至
synchronized (words){...}
但我所有的尝试都失败了,很可能是因为我不知道 "synchronism" 在这种情况下意味着什么以及如何使用它.
- 请注意,paint 方法中的
invokeLater
一开始似乎没有用,因为我总是从 EDT 调用它,但是如果我不使用它, paint
的第一次调用就不会在创建 GUI 时工作(是因为它在 GUI 之前执行,尽管在 GUI 之后被调用?
- 我显然缺乏很多概念,因此将不胜感激。
通过发布在 SwingWorker 中创建的 words
列表并继续处理同一实例,您可以使该实例服从同步。您应该更改 doInBackground
方法来为发布创建一个新的 List
,如下所示:
public List<Word> doInBackground() {
List<Word> words = new ArrayList<Word>();
while (!isCancelled()) {
// do some work, define aNewWord
words.add(aNewWord);
publish(new ArrayList<>(words)); // don't publish words directly but create new list
Thread.pause(someTime);
}
return words;
}
通过此更改,后台作业和您的绘画方法正在处理不同的对象,您的问题应该得到解决。
访问正在另一个线程 (SwingWorker) 中处理的列表时如何避免 java.util.ConcurrentModificationException
?
我正在尝试使用的详细信息:
一个 GUI class,其中包含此 "main" 方法,我认为应该 运行 在 EDT 上。
public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new myGUIwithButton(); } }); }
这个 GUI 有一个绘制方法,它获取
Words
的列表,一个包含字符串和坐标的 class,并显示它们:public void paint(final List<Word> words){ SwingUtilities.invokeLater(new Runnable() { public void run() { // prepare GUI's background, then : for(Word word : words){ // <-- this is line 170 in the error shown below // show each word in the GUI // note that I'm not modifying the words list here }
在 GUI 中按下按钮时,将执行 class 扩展
SwingWorker<List<Word>,List<Word>>
的实例。据我所知,这会创建工作线程。重写的doInBackground
方法创建一个单词列表,然后定期发布它:public List<Word> doInBackground() { List<Word> words = new ArrayList<Word>(); while (!isCancelled()) { // do some work, define aNewWord words.add( aNewWord ); publish(words); Thread.pause(someTime); } return words; }
然后自动将发布的单词发送到重写的
process
方法:protected void process(List< List<Word> > wordss) { // Executed on EDT ! <3 // I'm taking only the first list that was published to avoid trouble List<Word> words = wordss.get(0); myGUI.paint(words); }
有什么问题?
当工作线程进入"fast"(停顿少于 50 毫秒)时,我经常在 paint
方法中的第 170 行遇到异常(GUI 文件称为 MotsFleches.java):
Exception in thread "AWT-EventQueue-1" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at MotsFleches.run(MotsFleches.java:170)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at org.GNOME.Accessibility.AtkWrapper.dispatchEvent(AtkWrapper.java:700)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
paint
方法中的 words
列表似乎在 EDT 处理它时被修改。我没有在那里修改它,所以它必须来自其他线程?
我认为该列表只是另一个线程中 words
列表的 "snapshot",因为它是使用 publish
方法发送的。显然不是。
那么我应该更改什么才能在 EDT 方法中使用 SwingWorker
中已发布列表的 "snapshot"?
感谢您提供的任何建议。
备注
- 异常后,程序保持运行ning正常。我只想让它更干净。
- 我试着查看 Collections.synchronizedList() 甚至
synchronized (words){...}
但我所有的尝试都失败了,很可能是因为我不知道 "synchronism" 在这种情况下意味着什么以及如何使用它. - 请注意,paint 方法中的
invokeLater
一开始似乎没有用,因为我总是从 EDT 调用它,但是如果我不使用它,paint
的第一次调用就不会在创建 GUI 时工作(是因为它在 GUI 之前执行,尽管在 GUI 之后被调用? - 我显然缺乏很多概念,因此将不胜感激。
通过发布在 SwingWorker 中创建的 words
列表并继续处理同一实例,您可以使该实例服从同步。您应该更改 doInBackground
方法来为发布创建一个新的 List
,如下所示:
public List<Word> doInBackground() {
List<Word> words = new ArrayList<Word>();
while (!isCancelled()) {
// do some work, define aNewWord
words.add(aNewWord);
publish(new ArrayList<>(words)); // don't publish words directly but create new list
Thread.pause(someTime);
}
return words;
}
通过此更改,后台作业和您的绘画方法正在处理不同的对象,您的问题应该得到解决。