2009-05-10 8 views
0

私は、同じカスタムTreeModelクラスの異なるインスタンス(異なるオプションを使用)を使用して、私のアプリでJTreeをたくさん持っています。 getChildren()メンバの実行に時間がかかるため、SwingWorkerサブクラスをTreeModelに追加し、getChildren()でそのワーカーのインスタンスを作成して実行してから、 get()の結果を返します。TreeModelを更新するSwingWorker?

私はConcurrentModificationExceptionsを取得し続けています。私は何かを同期させるはずですが、何がわからないのか知っています。誰でも私のTreeModelを安全に応答させる方法について提案はありますか?

ありがとうございました! Joshua

+1

であなたのTreeModel内のデータを格納してみてください?そして/または例外スタックトレース? – harto

答えて

2

まず、スレッドを使用して高速化を試みているのはなぜかと思います。それはCPUバインド操作、またはネットワーク/ディスクバインドですか?

あなたの説明は、あなたのgetChildrenが完了するのを待ってから返されます。これは、マルチコアハードウェア上で並列処理が可能な場合に便利ですが、一般的なモデルではありません。通常、私たち(そしては何か)は、ブロックを別のスレッドで実行することです。イベントディスパッチスレッドは、バックグラウンドスレッドからデータを処理するイベントを受け取るまで自由に実行できます。

SwingWorkerはどこにでもConcurrentModificationExceptionをスローすることを文書化していません。スタックトレースが役立つかもしれません。

一般的には、SwingWorkerを避けることをお勧めします。小さなデモ操作を作成するのに最適ですが、貧弱なデザインが適用されます。

スレッド化は困難です。特に、マルチスレッド化されたハードウェアは実際にはより多くのバグがあります。リベラルな散水は​​で問題は解決しません。比較的簡単な一般的なアプローチは、変更可能なオブジェクトを共有すること(または少なくとも共有オブジェクトを変更すること)を避けることです。 EDTで使用されていないバックグラウンドスレッドに一連の引数を渡します。同様に、別の方法で変更されていないEDTに引数を戻します。

1

ConcurrentModificationExceptionsは、2つのスレッドで同じListにアクセスすると発生します。あなたのTreeModelはおそらくArrayLists、Vectors、Hashtables、またはノードを格納するのに似たものを使用します。

1)あなたのTreeModelのは常にEDTのスレッドでJTreeのことで、それがレンダリングされるたびに照会されます。

私の推測では、2つのいずれかが起こっているということです。これはやむを得ないことであり、Swingの仕組みです。ツリーモデルにアクセスしたり、別のスレッド上の基になるリストにアクセスしている場合は、レンダリングと同時にそのリストを実行し、Listが例外をスローします。

2)2人のスイングワーカーがそれぞれ独自のスレッドで動作しています。彼らは同時にリストを更新/照会しています。上記と同じ問題。

Tomとは、SwingWorkerを使ってTreeModelを「非同期」にすることは非常に難しい問題であり、避けるべきです。しかし、あなたの質問に答えるために、私は次のコードを見ていきます。ツリーに対するすべてのクエリおよび更新アクションが、EDTで常に実行される「完了」メソッドでどのように行われるかに注目してください。私の推測では、construct()メソッドでgets/setsをやっているということです。

 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(); 
} 
関連する問題