SwingWorker для обновления TreeModel? - PullRequest
0 голосов
/ 11 мая 2009

В моем приложении много JTree, все используют разные экземпляры (с разными опциями) одного и того же пользовательского класса TreeModel. Я пытаюсь добавить некоторые потоки, чтобы ускорить процесс, так как член getChildren () требует времени для запуска, я добавил подкласс SwingWorker в TreeModel и в своем getChildren () я создаю экземпляр этого работника и выполняю его затем верните результат get ().

Я получаю исключения ConcurrentModificationException и знаю, что должен что-то синхронизировать, но не уверен, что именно. Кто-нибудь получил какие-либо предложения о том, как обеспечить безопасную работу моего TreeModel?

Спасибо! Joshua

Ответы [ 3 ]

2 голосов
/ 11 мая 2009

Во-первых, мне интересно, почему вы пытаетесь использовать потоки, чтобы ускорить процесс. Это операция с процессором или сеть / диск?

Ваше описание выглядит так, как будто ваш getChildren ждет завершения операции, прежде чем вернуться. Это может быть полезно для параллельной работы на многоядерном оборудовании, но это не общая модель. Обычно то, что мы (и что делает SwingWorker), - это запуск кода блоков в другом потоке, в то время как поток рассылки событий может продолжаться, пока не получит событие для обработки данных из фонового потока.

SwingWorker не документирует, что он выбрасывает ConcurrentModificationException в любом месте. Может пригодиться трассировка стека.

Я обычно советую избегать SwingWorker. Это отлично подходит для создания небольшой демонстрационной операции, но накладывает плохой дизайн.

Многопоточность затруднительна, особенно сейчас, когда многопоточное оборудование на самом деле содержит больше ошибок. Либеральное опрыскивание synchronized не заставит проблемы уйти. Относительно простой общий подход заключается в том, чтобы избежать совместного использования изменяемых объектов (или, по крайней мере, изменения общих объектов). Передайте набор аргументов в фоновый поток, которые не используются в EDT. Аналогично, передайте аргументы обратно в EDT, которые не изменяются иным образом.

1 голос
/ 11 мая 2009

ConcurrentModificationExceptions возникают, когда вы обращаетесь к одному и тому же списку в двух потоках. Ваша TreeModel, вероятно, использует ArrayLists, Vectors, Hashtables или что-то подобное для хранения узлов.

Я предполагаю, что происходит одна из двух вещей:

1) Ваш TreeModel постоянно запрашивается JTree в потоке EDT при каждом его рендеринге. Это неизбежно и как работает Swing. Если вы обращаетесь к древовидной модели или нижележащим спискам в другом потоке, вы иногда делаете это одновременно с рендерингом, и List вызывает исключение.

2) у вас работают два рабочих свинга, каждый в своих потоках. Они одновременно обновляют / запрашивают список. Та же проблема, что и выше.

Я согласен с Томом, что использование SwingWorker для того, чтобы сделать вашу TreeModel "асинхронной", является очень сложной проблемой, и ее следует избегать. Но, чтобы ответить на ваш вопрос, я бы посмотрел следующий фрагмент кода. Обратите внимание, как все действия по запросу и обновлению дерева выполняются в «готовом» методе, который всегда выполняется в EDT. Я предполагаю, что вы делаете get / sets в методе construct ().

     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();
} 
0 голосов
/ 11 мая 2009

Возможно, попробуйте сохранить данные в TreeModel в CopyOnWriteArrayList

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...