Java-SwingWorker-如何使用EDT中发布的arraylist
在访问另一个线程(SwingWorker)中正在处理的列表时,如何避免Java-SwingWorker-如何使用EDT中发布的arraylist,java,user-interface,arraylist,swingworker,Java,User Interface,Arraylist,Swingworker,在访问另一个线程(SwingWorker)中正在处理的列表时,如何避免java.util.ConcurrentModificationException 有关我尝试使用的内容的详细信息: 一个包含这个“main”方法的GUI类,我认为应该在EDT上运行 public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() {
java.util.ConcurrentModificationException
有关我尝试使用的内容的详细信息:
- 一个包含这个“main”方法的GUI类,我认为应该在EDT上运行
public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new myGUIwithButton(); } }); }
- 此GUI有一个绘制方法,它获取
,一个包含字符串和坐标的类,并显示它们:单词列表
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 }
- 然后,发布的单词将自动发送到覆盖的
方法:过程
EDT正在处理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); }
方法中的绘制
列表时,该列表似乎正在被修改。我没有在那里修改它,所以它必须来自另一个线程?单词
我认为这个列表只是另一个线程中
列表的“快照”,因为它是通过单词
方法发送的。显然不是。 那么,在EDT方法中使用publish
中发布的列表的“快照”时,我应该做哪些更改? 谢谢你提供的任何建议 笔记SwingWorker
- 异常发生后,程序将继续正常运行。我只想把它弄干净
- 我试图查看甚至
,但我所有的尝试都失败了,很可能是因为我不知道“synchronizem”在本例中的含义以及如何使用它synchronized(words){…}
- 注意,paint方法中的
一开始似乎没用,因为我总是从EDT调用它,但是如果我不使用它,invokeLater
的第一次调用在GUI创建时不起作用(是不是因为它在GUI之前执行,尽管在GUI之后被调用paint
- 我显然缺乏很多概念,所以细节将非常感谢
列表并继续在同一实例上工作,您可以使此实例受到同步。您应该更改单词
方法,为发布创建新的doInBackground
,如下所示:列表
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; }
公共列表doInBackground(){ List words=new ArrayList(); 而(!isCancelled()){ //做一些工作,定义一个世界 添加(aneword); publish(newarraylist(words));//不直接发布单词,而是创建新列表 暂停(某个时候); } 返回单词; }
通过此更改,背景工作和绘制方法正在处理不同的对象,您的问题应该得到解决。要提出具体的建议有些困难,因为代码片段是零碎的,我们必须将其拼凑在我们的头脑中。如果您能提供一个简单的解决方案,那么就更容易了。至于问题:您正在使用相同的到处引用列表,这就是为什么会出现异常。作为第一步,要创建快照,只需在
中手动创建一个新列表,并将其传递到doInBackground
。看看这是否有帮助。我知道使用“SSCCE”会更好,但是我觉得自己没有能力做到这一点,因为重现问题需要SwingWorker执行一项“长”任务,在此期间它会更改列表,因此我认为我无法暂停模拟它。无论如何,幸运的是,我的问题出在我选择的几行代码中。:)它可以工作,谢谢!我简直不敢相信我离解决这个问题这么近:在提出问题之前,我试着用画法创建一个副本,但没有成功。这很奇怪,因为我刚刚试过,它也解决了问题。我第一次一定是做错了。在paint中创建一个新列表不会起作用,至于创建新列表,您也需要迭代到旧列表。它可能会降低问题发生的可能性,但您会不时遇到异常。实际上,这就是并发性成为编程中最困难的方面之一的原因。仅仅通过多次执行您的代码,您不能说:我确信它是有效的。您需要了解线程可以采取的不同路径,并始终假设最坏的情况。publish
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$2.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.access$500(EventQueue.java:97) at java.awt.EventQueue$3.run(EventQueue.java:709) at java.awt.EventQueue$3.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$5.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)
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; }