Помогите с реализацией Runnable в Java - PullRequest
1 голос
/ 22 сентября 2010

Я работаю над проектом Java с моей командой на работе. Подводя итог, у нас есть основной класс, который имеет метод, который создает экземпляр и вызывает класс «Сохранить». Этот класс «Save» сохраняет файлы обратно на сервер с помощью пары конструкторов и нескольких видимых и невидимых методов. Этот класс требует значительных ресурсов процессора и занимает много времени, что не позволяет основному приложению отображать диалоговое окно индикатора выполнения, информирующее пользователя о состоянии сохранения. Они попросили меня изменить класс «Сохранить» таким образом, чтобы он порождал свой собственный поток, чтобы остальная часть основного приложения могла выполнять меньшие задачи по отображению информации для пользователя.

Вот общая концепция этого:

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?

Если вам нужно больше деталей, пожалуйста, дайте мне знать. Спасибо за понимание!

Обновление: Спасибо всем за помощь! Эти решения пригодятся в будущем.

Ответы [ 4 ]

7 голосов
/ 22 сентября 2010

Самый простой способ - сделать работоспособным для каждого.Вместо того чтобы передавать параметры в run, сделайте их полями экземпляра.

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 выполняется, когда он передается в конструктор Thread , а затем в этом потоке вызывается start () .

3 голосов
/ 23 сентября 2010

Ваши коллеги, вероятно, вызывают 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;
       }
   }
 }
2 голосов
/ 22 сентября 2010

Полное решение заключается в расширении класса Runnable и передаче требуемых параметров и типа сохранения, необходимого для конструктора.Затем вы можете запустить их с помощью:

new Thread(saveRunnable).start();

Более простым решением было бы реализовать шаблон, подобный этому, внутри класса сохранения:

public void saveThis(StatusWindow s) {
  Runnable r = new Runnable() {
     private StatusWindow s;
     public Runnable setStatusWindow(StatusWindow s) {
       this.s = s;
       return this;
     }

     @Override
     public void run() {
       this.Save.saveThisInternal(this.s);
     }
  }.setStatusWindow(s);
  new Thread(r).start();
}

public void saveThisInternal(StatusWindow s) {
  //alot of code
  s.update();
}
0 голосов
/ 22 сентября 2010

Есть два способа сделать это:

a) Вы можете переместить код с помощью блока if в метод run ().

b) У вас может быть один класс наТип документа, который реализует выполняемый.

Подход а) проще, потому что он требует меньше изменений в существующем коде.Но подход b) - это объектно-ориентированный способ сделать это: «Один класс на задачу».

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