2012-01-06 18 views
3

すべて、Java Asyncのデータロードと進捗状況とスレッドの悪夢

私たちのアプリケーションではデータのロードに問題があります。現在の実装の目的は、データロードのための非同期メカニズムを持つことでした。

私は基本的にこれに良いパターンや習慣があるかどうかを知りたいと思っています。

アプリケーションには、標準的な方法でコード化されていないさまざまなUIコンポーネントがあります。それはすべて構成(すなわちxml)から生成されます。データロードは、データローダーに非同期メッセージを送信するカレンダーをクリックすることによってトリガーされます。データローダーには、データベースからデータをロードする約6つのインスタンス(同じクラスのインスタンス)があります。データがロードされて処理されると、データローダクラスは、それを表示するJTableに非同期的にテーブルデータを送信します。

データのロードには1秒から2時間かかります分、進捗ダイアログが必要でした。データロードの開始/完了時に、データローダーからのイベントをリスンするための追加のクラスが作成されました。データローダが読み込みを開始すると、データが読み込まれていることを示すダイアログが表示されます。最後のデータローダーが完了したら、ダイアログを非表示にする必要があります。

現在の問題/課題

発生2つの問題があります。

  • 時々ダイアログは、データローダの全てが完了しているにもかかわらず、表示されたままになりますが。
  • その他の場合、データが表に表示されないことがあります。

私たちは、進行中の表示方法と非表示方法の周りにsynchronizedキーワードを追加しようと無駄にしようとしましたが、それと同様に発行されました。私はある種のリライトが順調であると思いますが、非同期Javaパターンについてもう少し理解したいと思います。このメカニズムは、より強固で信頼性の高いものでなければなりません。

現在のプロセス

私たちの現在のプロセスでは、あなたの興味があれば、私は以下のイベントを要約することを試みました。これは、設計/実装の問題を明らかにするかもしれない。

  1. カレンダーのユーザーのクリック数。

    カレンダーコンポーネントは、それぞれのデータローダーインスタンスに、読み込み開始を知らせるメッセージを送信します。このメッセージは、別のスレッド(2)で非同期にカレンダーから送信されます。

  2. データローダは、ロード・メッセージ

    を受信した各データローダは、関連データをロードして表示する表に渡す責任があります。

    各データローダには、データがロードされる単一のスレッドインスタンスがあります。現在のスレッド・ロード・インスタンスが設定され、データをロードしている場合、ロードは中止されます。これは、カレンダー内のクイック・クリックから発生する可能性があります。新しいスレッドインスタンスは、データロードスレッドがアイドルまたはヌルになると作成され、開始されます。

    データロードスレッドは、データアクセスと処理を実行します。起動されると、DataLoadDialogクラスに通知されます(3)。このDataLoadDialogは、基本的にリスナー(DataLoaderListener extends EventListener)をEventListenerListに追加します。データスレッドがロードされると、DataLoaderListener.loadStartが呼び出されます。これはDataLoadDialogによって取得されます。スレッドがデータをロードして処理すると、DataLoaderListener.loadCompleteが呼び出されます。これはDataLoadDialogで再び取り上げられます。

    データがロードされたので、DataLoaderはデータをテーブルに送信して表示します。

  3. は、負荷状態

    DataLoadDialog各データローダへの参照を持つのDataLoadDialogを通知します。各データローダーは、ゲッターを介してアクセスされるステータスを持ち、IdleまたはLoadingの列挙型を返します。 DataLoadDialogは、loadStartまたはloadCompleteの呼び出しを受け取るたびに、データロードスレッドの状態に応じて進行状況ダイアログを表示するかどうかを決定します。

    プロセスダイアログは、(構成XMLから)クラスが作成されたときに作成されるシングルトンの静的インスタンスです。

助けてください。私が何かを逃した場合は、コメントを追加してください、私は質問を更新します。

おかげで、

Andez

答えて

0

私はSwingWorkerを調べました。私はこれらの例を試しましたが、SwingWorkerから各DataLoaderを生成することが考えられます。

私はこれに反対することを決め、DataLoadDialogクラスとSwing JDialogの間のやりとりがどのように進行するかという問題を発見しました。私は私の例をあまりに単純化しました。さらに2つのコンボがあり、データの読み込みがトリガーされました。 1つのコンボは、3つのデータローダーにローディングを開始させ、もう1つのコンボは別の3つのデータローダーに強制します。それは、システムが書かれている方法のために厄介な余分な設定を追加することになります。

私は最初にsynchronizedキーワードをloadStartとloadCompleteに追加しようとしましたが、これはまだ問題を解決しませんでした。私はまた、ダイアログが表示され/隠された場所にinvokeAndWaitを持っていました。私は、これによって複数のスレッドが進行状況の表示/非表示を試みるのを防ぐことができると期待していましたが、そうではありませんでした。私はinvokeAndWaitをトリックをしたようなinvokeLaterに置き換えました。

私はSwingWorkerに完全に同意しています。このようなシナリオは、設計上より詳細にレイアウトする必要があります。私たちはここでは悪いですが、私はそれが嫌いです。同時のソリューション全体は、最初のデータを同期してロードするのに約20分かかった後に組み合わされました.1台のローダーがデータベースから順番にデータを取得します。ロードされるデータの量は非常に恐ろしいです - それはまた、何らかの調整を実行しなければなりませんでした。

Andez

3

問題は基本スイングル​​ールの違反のように聞こえる: EDT上で行われる必要があり、すべてのコンポーネントにアクセスできます。 EDTですべてのユーザーのフィードバック(ダイアログの表示/非表示、プロセス状態の更新、表データの更新)が行われていることを確認してください。

これを行うのに役立つクラスはSwingWorkerです。そのAPIドキュメントは非常に広範で、モデル/コンポーネントに直接アクセスする方法の例があります。

にPropertyChangeEventを介して中間データを渡すことによって、実際のUIから作業者を少し分離する方法を示すいくつかの擬似コードスニペット:

// on user click (here we are on EDT), 
// open the dialog, create the loader, add a PropertyChangeListener and start 
showProcessDialog(); 
MySwingWorker worker = new MySwingWorker(); 
PropertyChangeListener l = new PropertyChangeListener() { 
    public void propertyChanged(....) { 
     if (StateValue.DONE == evt.getNewValue) { 
      closeProcessDialog(); 
     } 
     if ("chunkAvailable".equals(evt.getPropertyName()) { 
      addChunkToTable((ChunkType) evt.getNewValue()); 
     } 
    }  
} 
worker.addPropertyChangeListener(l); 
worker.execute(); 

// custom implementation of SwingWorker 
public MySwingWorker extends SwingWorker<ResultType, ChunkType> { 

    @Override 
    protected <ResultType> doInBackground() { 
     // here we are in the worker thread 
     // start the actual loaders 
     Dataloaders loaders = .... 
     // process their result/s 
     ResultType endResult = ...; 
     while (...) { 
      ChunkType intermediateResult = .... 
      // possibly produce some end result 
      endResult = ... 
      // publish the intermediate chunk 
      publish(intermediateResult); 
     } 
     return endResult; 
    } 

    @Override 
    protected void process(List<ChunkType> chunks) { 
     // here we are on the EDT, so it's safe to either notify swing listener 
     // or access swing components/models directly (as shown in the api/tutorial example) 
     for(ChunkType chunk: chunks) { 
      PropertyChangeEvent e = new PropertyChangeEvent(this, "chunkAvailable", null, chunk); 
      getPropertyChangeSupport().firePropertyChange(e); 
     } 
    } 

} 
+0

ありがとうございました。それを調べます。 SwingWorkerがこれまでに述べたことを聞いたことがあります。私の頭の中で、それが私たちのアプリケーション全体にどのようにフィットするかを知る必要があります。- – Andez

+0

@kleopatra:何か追加できますか? SwingWorkerについて、ちょっと奇妙だけど、Netbeansを使ってデバッグした後に...あまりにも多くのSwingWorker-pool-threadが生きているのですが、これは何が起こったのでしょうか? – gumuruh

2

@のクレオパトラの説得力のある提案に加えて、articlehereの方法について説明に引用既存のコードでEDT違反が見つかりました。より多くの例hereおよびhere

関連する問題