首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >要更新TreeModel的SwingWorker?

要更新TreeModel的SwingWorker?
EN

Stack Overflow用户
提问于 2009-05-10 23:34:54
回答 3查看 1.3K关注 0票数 0

我的应用程序中有很多JTree,它们都使用同一个自定义TreeModel类的不同实例(具有不同的选项)。我正在尝试添加一些线程来加快速度,因为getChildren()成员需要一段时间才能运行,所以我在TreeModel中添加了一个SwingWorker子类,并在getChildren()中创建了该worker的一个实例并执行它,然后返回它的get()结果。

我不断得到ConcurrentModificationExceptions,我知道我应该同步一些东西,但不确定是什么。有没有人对如何让我的TreeModel安全响应有什么建议?

谢谢!约书亚

EN

回答 3

Stack Overflow用户

发布于 2009-05-11 00:43:44

首先,我想知道您为什么要尝试使用线程来提高速度。是CPU绑定的操作,还是网络/磁盘绑定的操作?

您的描述看起来像是您的getChildren在等待操作完成后才返回。这可能对多核硬件上的并行操作很有用,但不是通用模型。通常我们(和SwingWorker所做的)是在另一个线程上运行代码块,而事件分派线程可以自由运行,直到它接收到一个事件来处理来自后台线程的数据。

SwingWorker没有说明它抛出了ConcurrentModificationException anywhere。堆栈跟踪可能会有所帮助。

我通常建议避免使用SwingWorker。它很适合创建一个小的演示操作,但却强加了一个很差的设计。

线程是困难的,特别是现在多线程硬件实际上有更多的bug。随意使用synchronized并不会让问题消失。一种相对简单的通用方法是避免共享可变对象(或至少更改共享对象)。将EDT中未使用的一组参数传递到后台线程。同样,将未被修改的参数传递回EDT。

票数 2
EN

Stack Overflow用户

发布于 2009-05-11 01:47:55

当你在两个线程上访问相同的列表时,就会发生ConcurrentModificationExceptions。您的TreeModel可能使用ArrayLists、Vectors、Hashtables或类似的东西来存储节点。

我的猜测是发生了以下两件事之一:

1)您的TreeModel在每次呈现时都会不断地被EDT线程上的JTree查询。这是不可避免的,也是Swing的工作原理。如果您正在访问树模型或位于不同线程上的底层列表,则偶尔会在呈现和列表抛出异常的同时执行此操作。

2)您有两个swing工作线程在运行,每个都在各自的线程上。它们同时更新/查询列表。和上面的问题一样。

我同意汤姆的观点,使用SwingWorker使你的TreeModel“异步”是一个非常棘手的问题,应该避免。但是,为了回答您的问题,我将查看以下代码。请注意,对树的所有查询和更新操作都是在"finished“方法中进行的,该方法总是在EDT上运行。我的猜测是您在construct()方法中执行get/set。

代码语言:javascript
复制
     public TreeNode[] getChildren(TreeNode parent){

         // Do all normal work you would do
         ...


         // figure out if this parents children have not been fetched yet
         boolean needToFetch = ....

         if(needToFetch){

          worker = new SwingWorker() {
           public Object construct() {
            // go fetch your children from whatever database, server, file...
            // fetchNewChildren must NOT access the TreeModel or any of the underlying
            // lists, because you will get a modification exception.  This is what
            // Tom meant by "Pass a set of arguments into the background thread 
            // that are not being used in the EDT"

            return fetchNewChildNodes(parent);
          }

          public void finished() {
            List<TreeNode> newNodes = (List<TreeNode>)get();

            // insert the newly fetched nodes into the parent
            // if done correclty, this will fire TreeModelChanged events
            // so the tree should re-render, repaint, etc...
            parent.addChildren(newNodes); 
         }
         };

         worker.start();
} 
票数 1
EN

Stack Overflow用户

发布于 2009-05-11 02:10:16

也许可以尝试将数据存储在CopyOnWriteArrayList中的TreeModel中

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/846317

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档