1

私は自分のチームが働いているJavaプロジェクトに取り組んでいます。要約すると、「保存」クラスをインスタンス化して呼び出すメソッドを持つメインクラスがあります。この「保存」クラスは、いくつかのコンストラクターといくつかの表示および非表示メソッドを使用してファイルをサーバーに保存します。このクラスはCPUに負荷がかかり、時間がかかるため、メインアプリケーションがプログレスバーダイアログウィンドウを表示して、ユーザーに保存のステータスを知らせることができません。彼らは、メインアプリケーションの残りの部分がユーザーに情報を表示するという小さなタスクを実行できるように、独自のスレッドを生成するように「保存」クラスを変更するように私に依頼しました。

その一般的な概念は次のとおりです。

class MainApp{  
    ...

    private void doSave()
    {
        Save s = new Save();
        StatusWindow sw = new StatusWindow();

        if save_this
          s.saveThis(sw);
        if save_that
          s.saveThat(sw);

        ...
    }
    ...
}

class Save{
   ...

   public void saveThis(StatusWindow s)
   {
       //alot of code
       s.update;

   }
   public void saveThat(StatusWindow s)
   {
       //alot of code
       s.update;
   }
   ... // some non-visible methods, even more code
 }

私は現在Javaのスレッドの初心者ですが、スレッドがどのように機能するかについての基本的な理解があります。私が理解していることから、Runnableを実装するクラスは、新しいスレッドとしてインスタンス化されると、run()メソッドが実行されます。問題は、ファイルの種類ごとに保存の種類ごとに異なるメソッドがあるため、これらのメソッドをrun()メソッドに実装するにはどうすればよいですか?run()メソッドは、クラスが新しいスレッドでインスタンス化され、.start()が呼び出されたときに実行される唯一のメソッドですか?

この問題の良い解決策は何でしょうか?Runnableを実装するには、「Save」クラスを再設計する必要がありますか?

詳細が必要な場合はお知らせください。洞察をありがとう!

更新:助けてくれてありがとう!これらのソリューションは、将来的に役立ちます。

4

4 に答える 4

7

最も簡単な方法は、それぞれに対して実行可能にすることです。パラメータが実行に渡される代わりに、それらをインスタンスフィールドにします。

class SaveThatCommand implements Runnable {
     private final StatusWindow s;
     //constructor that initializes s
     public void run() {
        //save that code
        s.update();
     }
}

要件に応じて、これを実現する簡単な方法は、匿名の内部クラスを作成することです。

public void doSave(final StatusWindow s) {
    if (saveThis) {
        Thread t = new Thread( new Runnable() {
            public void run() {
               saveThis(s);
            }
        });
        t.start();
    }
    //...
}

そして、あなたは少し間違っています。runメソッドは、スレッドのコンストラクターに渡されたときに実行され、そのスレッドでstart()が呼び出されます

于 2010-09-22T19:36:56.700 に答える
3

同僚はおそらくメインアプリケーションの複数の場所からSaveを呼び出し、並列操作としての保存をサポートするために他のすべてのコードを変更する必要を避けたいと考えています。また、一般的に、ほとんどの人は独自のスレッドを作成することを好みません。代わりに、ExecutorServiceを使用することを好みます。したがって、Saveクラスを変更し、エグゼキュータを使用するだけでそれを行う方法は次のとおりです。

class Save{
   private static final ExecutorService executor = Executors.newCachedThreadPoolExecutor();
   //or fixed, or whatever you want. Maybe single thread executor is best if the Save code is not well suited to concurrency.

   static {
       Runtime.getRuntime().addShutdownHook(
           new Thread() {
               public void run() {
                   executor.shutdown();
               }
           }
       );
   }

   public void saveThis(StatusWindow s)
   {
      executor.execute(new SaveThis(s));
   }
   public void saveThat(StatusWindow s)
   {
      executor.execute(new SaveThat(s));
   }
   ... // some non-visible methods, even more code

   private class SaveThis implements Runnable {
       //StatusWindow member variable and constructor
       public void run() {
           //alot of code
           s.update;
       }
   }

   private class SaveThat implements Runnable {
       //StatusWindow member variable and constructor
       public void run() {
           //alot of code
           s.update;
       }
   }
 }
于 2010-09-23T02:17:05.820 に答える
2

完全な解決策は、クラスを拡張し、Runnable必要なパラメーターと必要な保存のタイプをコンストラクターに渡すことです。次に、それらを次のように実行できます。

new Thread(saveRunnable).start();

より簡単な解決策は、saveクラス内に次のようなパターンを実装することです。

public void saveThis(StatusWindow s){
  Runnable r = new Runnable(){
     プライベートStatusWindows;
     public Runnable setStatusWindow(StatusWindow s){
       this.s = s;
       これを返します。
     }

     @オーバーライド
     public void run(){
       this.Save.saveThisInternal(this.s);
     }
  } .setStatusWindow(s);
  new Thread(r).start();
}

public void saveThisInternal(StatusWindow s){
  //たくさんのコード
  s.update();
}
于 2010-09-22T19:44:49.777 に答える
0

これを行うには2つの方法があります。

a)if-blockを使用してコードをrun()メソッドに移動できます。

b)runnableを実装するドキュメントタイプごとに1つのクラスを持つことができます。

アプローチa)は、既存のコードへの変更が少なくて済むため、より簡単です。しかし、アプローチb)は、それを行うためのオブジェクト指向の方法です。「タスクごとに1つのクラス」です。

于 2010-09-22T19:41:52.157 に答える